Close your terminal, reopen it, and find yourself exactly where you left off: that's what tmux makes possible. You launch a long SSH process, the connection drops: with tmux, it keeps running on the server side, your session intact.
Think of tmux as a building that never closes. The session is the entire building. A window is a floor with its elevator. A pane is a room where you put your editor in one corner and your logs in the other. Once that hierarchy clicks, everything else flows.
By the end of this article, you'll know how to create and reattach sessions, organize windows and panes. You'll configure Ghostty for true colors, share a session with a colleague, and add themes via a plugin manager.
tmux runs on a client-server architecture, and that's the key to everything. When you launch tmux, a server starts in the background and hosts your sessions; your terminal is just a client connecting to it. Detaching the client (closing the window, losing the SSH connection) doesn't kill the server: processes keep running. The official documentation says it clearly: a session "will survive accidental disconnection (such as ssh(1) connection timeout) or intentional detaching."
That's what sets tmux apart from a modern terminal's native tabs. Tabs live inside the graphical app: if it closes, they're gone. A tmux session lives on the shell side, independent of the interface. We come back to this in the Ghostty section.
Three concepts, from broadest to finest, structure everything:
Prerequisites are light: a terminal, shell access (macOS or Linux), and the willingness to memorize a handful of shortcuts. No prior tmux knowledge is needed. One piece of vocabulary to nail down right away, because it shows up everywhere: the prefix is the key combination that precedes every tmux command. By default it's Ctrl+b.
On macOS with Homebrew (macOS's package manager):
brew install tmuxOn Ubuntu or Debian:
Check the installed version:
tmux -VYou'll see something like tmux 3.7a (the stable release from June 2026). Note that apt on Ubuntu/Debian often installs a much older version than brew on macOS.
⚠️ Version frozen by your distribution. Since your tmux version is frozen, verify it with
tmux -V: some options mentioned later only apply from tmux 3.4+.
Start a first session and give it a name. The name is optional, but it's a good habit as soon as you have more than one:
tmux new -s devtmux opens. A status bar appears at the bottom, showing the session name, the list of windows, and the time. You're inside the session.

Every tmux command starts with the prefix Ctrl+b. The mechanism is precise: press Ctrl+b, release, then press the command key.
⚠️ tmux's number-one trap. The most common mistake is pressing
Ctrl+band the letter together, like a normal keyboard shortcut.
The most useful tmux command: detach the session without stopping what's running inside it. Press Ctrl+b, release, then d (for detach).
The terminal returns to normal, and you see:
[detached (from session dev)]The dev session is still running in the background. To list active sessions:
tmux lsdev: 1 windows (created Wed Jul 1 09:14:22 2026)To go back in:
tmux attach -t devEverything is exactly as you left it. A small clarification that corrects a widespread misconception: tmux attach without an argument doesn't only work when you have a single session. If several sessions exist, tmux automatically reattaches the most recently used one. The command only fails when there's no session at all.
A command worth knowing for daily use, the attach-or-create: it reattaches the session if it exists, and creates it otherwise. Perfect as a shell alias.
tmux new-session -A -s devtmux reads a config file at startup. Two possible locations:
~/.tmux.conf : the historic location, searched first.~/.config/tmux/tmux.conf : the modern location, following the XDG standard.It's not cumulative: only one user file is loaded, and ~/.tmux.conf wins if it exists. We'll use ~/.tmux.conf from here on.
Many people remap the prefix to Ctrl+a, out of habit from GNU Screen (tmux's ancestor, which uses Ctrl+a) or for keyboard comfort.
# Remap the prefix from Ctrl+b to Ctrl+a
set-option -g prefix C-a
unbind-key C-b
# Send a real Ctrl+a to the app (readline shortcut for beginning of line)
bind-key C-a send-prefixThis is where tmux gets genuinely useful.

A window is a tab inside the session. Create one with Ctrl+b then c (for create). The status bar now shows two windows, 0:bash and 1:bash*: the asterisk marks the active window.
To navigate:
Ctrl+b n → next window (next)Ctrl+b p → previous window (previous)Ctrl+b 0, Ctrl+b 1, … → direct access by numberBy default, numbering starts at 0 (the base-index option).
To rename the current window: Ctrl+b ,. To rename the whole session: Ctrl+b $. This helps enormously as soon as you juggle several contexts (api, db, logs).
A pane is a split inside a window. Two ways to split:
Ctrl+b % → vertical split (two columns side by side)Ctrl+b " → horizontal split (two stacked rows)To move between panes: Ctrl+b then the arrow keys.
Two shortcuts to keep handy:
Ctrl+b z → zoom the active pane (it fills the screen). Press Ctrl+b z again to return to the layout.Ctrl+b q → shows each pane's number: type the number while it's displayed to jump there.To close a pane, type exit (or Ctrl+d) in its shell. To kill it directly: Ctrl+b x (kill-pane, with a y/n confirmation). To kill a whole window: Ctrl+b & (kill-window, also confirmed).
There's no dedicated "mode," just repeatable shortcuts (release the prefix, then repeat the key within 500 ms):
Ctrl+b then Alt+↑ / ↓ / ← / → → resize in steps of 5 cellsCtrl+b then Ctrl+↑ / ↓ / ← / → → in steps of 1 cellFrom the command line, resize-pane gives fine control:
tmux resize-pane -D 5 # grow downward by 5 rows
tmux resize-pane -U 10 # upward by 10 rows
tmux resize-pane -x 80 # absolute width: 80 columns
tmux resize-pane -x 50% # width as a percentageCtrl+b Space (next-layout) cycles through ready-made arrangements. The five classics:
You can duplicate your keyboard input across all panes of a window at once:
tmux setw synchronize-panes onThe concrete DevOps use case: open one SSH pane per server, turn synchronization on, type sudo apt update && sudo apt upgrade -y once: the command runs everywhere simultaneously. Then turn it off immediately (synchronize-panes off) so you don't accidentally send a command to every server.
Ctrl+b [ → enter copy-mode (copy/scroll mode). You navigate the history.Ctrl+b ] → paste the last copied buffer.Ghostty is a modern terminal, and if you use it, there's one thing to configure so you don't lose 24-bit colors (true color, 16 million colors) inside tmux.
The diagnosis first. Ghostty sets the TERM environment variable to xterm-ghostty. When tmux starts inside, it rewrites TERM for its own purposes, and if the config doesn't follow, you lose true color. Here's the up-to-date configuration, recommended by the official tmux documentation:
# tmux default terminal
set -g default-terminal "tmux-256color"
# Enable true color (RGB) for Ghostty
set -ag terminal-overrides ",xterm-ghostty:RGB"
# Same as terminal-overrides but for tmux >= 3.2
set -as terminal-features ",xterm-ghostty:RGB"Two points deserve an explanation, because many tutorials (and the old reflex) still recommend something else:
Why tmux-256color and not screen-256color? The official tmux wiki FAQ explains it: some applications inside tmux don't recognize keys well when TERM is screen or screen-256color, whereas the tmux and tmux-256color descriptions do have those capabilities. tmux-256color (provided by a modern ncurses) also supports italics, unlike screen-256color. The screen* family isn't "wrong," but tmux-256color has strictly superior capabilities.
Why :RGB and not :Tc? Again from the official FAQ: "RGB is the official flag, Tc is a tmux extension." The :Tc flag (for TrueColor) still works (it's not broken), but :RGB (a standard terminfo flag) is the recommended form today.
After editing the file, reload the config without leaving tmux:
tmux source-file ~/.tmux.conf⚠️ Trap. Run outside a tmux session, this command returns an error. Type it from inside a session.
Now we enter DevOps territory. tmux lets two people see and drive the same terminal in real time. This is called pair debugging, and it changes everything during an incident: two SREs look at the same logs and act together, with no screen sharing, no latency.
Two methods, from simplest to cleanest.
sudo -uTwo different accounts, marc and julie, on the same server. marc has a running session. If julie has sudo rights to act as marc, she joins in one command:
# From julie's side
sudo -u marc tmux attach -t devsudo -u marc launches tmux as marc: tmux automatically finds that session's socket. You can add -r for a read-only attach, but beware: -r is not a security mechanism (more on this in the Security section).
The prerequisite is heavy: julie must have sudo rights over marc, which is broad and not scoped to tmux. In return, sudo leaves an audit trail (in /var/log/auth.log, for example): a real advantage.
tmux -S)This is the recommended method for sharing without privilege escalation. A socket is the file through which the tmux client and server communicate. By default it lives in /tmp/tmux-<uid>/default, in a directory tmux creates itself with 0700 permissions (owner-only access). With -S, you choose its location, and that automatic protection disappears: security becomes entirely your responsibility.
# From marc's side: create the session on a dedicated socket
tmux -S /tmp/tmux-shared/dev.sock new -s dev
# Grant access to julie via a group (recommended approach)
mkdir /tmp/tmux-shared
chgrp devops /tmp/tmux-shared && chmod 770 /tmp/tmux-shared
chgrp devops /tmp/tmux-shared/dev.sock && chmod 770 /tmp/tmux-shared/dev.sock
# From julie's side (member of the devops group)
tmux -S /tmp/tmux-shared/dev.sock attachSince tmux 3.3 (2022), a native command completes the setup: server-access, an application-level ACL (Access Control List) for the socket.
tmux server-access -a julie # read-write access
tmux server-access -ar julie # read-only access
tmux server-access -d julie # revokeNote: server-access complements socket sharing, it doesn't replace it: the socket must already be accessible at the file level. On Debian bookworm (tmux 3.3+), you actually need tmux server-access -a $USER in addition to the socket chmod.
sudo -u and the shared socket| Criterion | sudo -u marc tmux attach | Shared socket -S |
|---|---|---|
| Prerequisite | sudo rights (broad, not scoped to tmux) | file access (group + chmod), no sudo |
| Access scope | the entire marc account via sudo | only this socket/session |
| Traceability | sudo logs the call (auth.log) | no native trail |
| Good use | when elevation is genuinely required | pair debugging by default, no elevation |
Here's how access flows in the socket method:
tpm (Tmux Plugin Manager, the official plugin manager) installs themes and plugins directly from your .tmux.conf. Think of Homebrew, but for tmux. Clone it first:
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpmThen declare the plugins in the config. Here's a complete file, so you see where each line goes:
# Ghostty config (from step 3)
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",xterm-ghostty:RGB"
# tpm plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'nordtheme/tmux'
# Required line: ALWAYS the last line of the file
run '~/.tmux/plugins/tpm/tpm'⚠️ The
runline must be the very last line of the file. This isn't a style preference: tpm needs all the@pluginlines to be read before it runs. Placed too early, some plugins won't load. It's the classic tpm mistake.
Reload, then install the plugins with Ctrl+b then I (capital, for Install):
tmux source-file ~/.tmux.confA banner appears (TMUX environment reloaded...), and the status bar takes on the arctic blue-grey tones of the Nord theme. Three tpm shortcuts to remember:
| Shortcut | Action |
|---|---|
Ctrl+b I | Install declared plugins |
Ctrl+b U | Update all plugins |
Ctrl+b Alt+u | Uninstall plugins removed from the file |
For other popular, actively maintained themes, look at catppuccin/tmux (very well maintained) or janoamaral/tokyo-night-tmux. And for sensible defaults in one line, tmux-plugins/tmux-sensible.

Two plugins go beyond styling: they make your sessions survive a full machine restart.
tmux-resurrect saves sessions, windows, and panes (with their order and exact layouts, even zoomed), working directories, and a configurable allowlist of programs to relaunch (default: vi vim nvim emacs man less more tail top htop irssi weechat mutt, extensible via @resurrect-processes). Important honesty note: it does not restore scrollback (the scroll history) by default, don't count on it. Shortcuts: prefix + Ctrl-s to save, prefix + Ctrl-r to restore.
tmux-continuum automates resurrect: it saves every 15 minutes by default, and auto-restores when the tmux server starts (not continuously). It requires @continuum-restore 'on' and strictly depends on tmux-resurrect: without it, nothing works. Adjust the interval with @continuum-save-interval.
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
set -g @continuum-restore 'on'
set -g @continuum-save-interval '15'| Symptom | Likely cause | Fix |
|---|---|---|
no server running on ... | no session, or different UID (via sudo -u), or an accidental kill-server | check tmux ls under the right account; start a session |
| Colors are dull / no true color | default-terminal or terminal-overrides misconfigured | apply tmux-256color + :RGB (step 3) |
source-file returns an error | command run outside a tmux session | type it from inside tmux |
| tpm plugins don't load | the run line isn't last | move run '.../tpm' to the end of the file |
| Lag when exiting Neovim's insert mode | escape-time too high | set -sg escape-time 10 |
You're in a local tmux, you SSH into a server that itself has a tmux: two nested tmux instances, and a single Ctrl+b prefix. To send a command to the remote tmux, double the prefix: Ctrl+b Ctrl+b then the key. The first Ctrl+b is consumed by the local tmux, the second is passed to the remote one. A more comfortable solution for heavy use: give the remote tmux a different prefix (Ctrl+a remote / Ctrl+b local).
A few options that make tmux nicer day to day:
# Number from 1 (aligned with the keyboard)
set -g base-index 1
set -g pane-base-index 1
# Longer scroll history (2000 lines by default)
set -g history-limit 50000
# Enable the mouse (select, resize, switch window)
set -g mouse on
# Status bar refresh rate (15 s by default)
set -g status-interval 5A history-limit of 2000 lines fills up fast with verbose logs; 50000 is comfortable. mouse on (off by default, unified since tmux 2.1) makes selection and resizing more intuitive. Watch status-interval: lowering it makes the display more responsive, but if your status bar runs heavy scripts, it costs CPU.
On footprint, tmux is remarkably light: the binary is about 900 KiB, written in C. That's a useful comparison point against Zellij (next section).
tmux isn't alone. Two alternatives come up often.
GNU Screen is the ancestor: created in 1987, written in C. Its latest version, 5.0.1 (May 2025), is a pure security release fixing three CVEs (CVE-2025-46802/46804/46805). Its cadence is that of slow corrective maintenance, with no new feature development. Screen stays relevant for one reason: its near-universal presence on old, restricted systems where you can't install anything.
Zellij is the modern challenger: written in Rust, launched around 2021, latest version v0.44.3 (May 2026). Its number-one asset is discoverability: a permanent contextual help bar shows available shortcuts, where tmux relies on the prefix and memory. It offers declarative layouts, persistent floating panes, and a WebAssembly plugin system (WASM, a portable binary format that runs anywhere) natively. Its config uses the KDL format. An honest nuance on size: its binary is about 38 MiB versus ~900 KiB for tmux, Rust isn't automatically as light as C here.
| Criterion | tmux | GNU Screen | Zellij |
|---|---|---|---|
| Age | 2007 | 1987 | ~2021 |
| Language | C | C | Rust |
| Latest stable (Jul 2026) | 3.7a | 5.0.1 | 0.44.3 |
| Release cadence | Regular | Very slow | Active |
| Binary size | ~900 KiB | Light | ~38 MiB |
| Learning curve | Medium-high | Medium | Low (built-in help) |
| Config | .tmux.conf | .screenrc | KDL |
| Plugin ecosystem | Large, proven (TPM) | Almost nonexistent | Young (WASM) |
| Default availability | Very wide | Near-universal | None, manual install |
| Excels at | DevOps/server, remote SSH | Old/restricted systems | Personal machine, modern UX |
The consensus isn't settled: migrations in both directions are reported. For DevOps use on remote servers, tmux remains the default choice thanks to its universal presence and proven ecosystem.
tmux turns a terminal into a persistent workspace: your sessions survive SSH drops, your screen splits into windows and panes, and two people can drive the same session in real time. The core gesture to internalize: tmux new -s <name> to create, Ctrl+b d to detach, tmux attach -t <name> to come back. The rest (panes, layouts, themes) builds on top, one command at a time.
Thanks for following me on this adventure! 🍺