cheat sheet
tmux
Run multiple persistent terminal sessions, windows, and panes inside one shell. Covers the session/window/pane mental model, default keybindings, copy-mode, and a minimal tmux.conf.
tmux — Terminal Multiplexer
What it is
tmux (terminal multiplexer) is an open-source program by Nicholas Marriott that lets a single terminal window host many independent shell sessions, organised into windows and split panes, and — crucially — keep them running when the controlling terminal closes. The killer use case is SSH: start work on a remote host, get disconnected, reconnect tomorrow, and resume exactly where you left off. As of 3.5 (Sept 2024) and 3.6 (2025), tmux is still under active development and gaining features like extended-key encoding, mirrored layouts, popup mouse handling, and finer-grained pane/window hooks.
The main alternatives are:
screen— the original GNU terminal multiplexer; older, simpler, often preinstalled, but no native panes and a much smaller config vocabulary.zellij— Rust competitor with floating panes, KDL configs, and an always-visible keybinding hint bar; far gentler learning curve, but younger ecosystem and slightly higher resource use.wezterm— a GPU-accelerated terminal emulator that bundles its own multiplexer (wezterm cli), so you get panes/tabs/sessions without a separate process; only useful if you also use wezterm as your terminal.
Pick tmux for stability, scriptability, and the largest plugin ecosystem; pick zellij for the friendliest out-of-the-box experience; pick wezterm if you already run it as your terminal and want one fewer moving part.
Install
tmux is packaged on every Linux distribution and is a single binary with no runtime dependencies. The system package is usually fine; build from source only if you need the latest features. Notable cut-offs: 3.2+ for display-popup, 3.4+ for menu/popup -T titles and the :Tc colour override generally working, 3.5+ for extended-keys mode 2 and mirrored main-* layouts, 3.6+ for pane-scoped hooks and the command-error hook.
# Debian/Ubuntu
sudo apt install tmux
# Fedora/RHEL
sudo dnf install tmux
# Alpine (containers)
apk add tmux
# macOS
brew install tmux
Output: (none — exits 0 on success)
Mental model: sessions, windows, panes
tmux has a strict three-level hierarchy. A session is the top-level container that survives detach/reattach; a window is like a browser tab inside a session; a pane is a split region inside one window. Most commands act on the current level, so knowing where you are matters.
| Level | Holds | Survives disconnect? | Typical use |
|---|---|---|---|
| Session | Windows | Yes (it's the whole point) | One per project or per remote host |
| Window | Panes | Yes (lives in its session) | One per major task ("editor", "logs", "server") |
| Pane | A single shell | Yes (lives in its window) | Split for side-by-side commands |
Session "work"
├─ Window 0 "editor"
│ ├─ Pane 0 (vim)
│ └─ Pane 1 (file tree)
├─ Window 1 "server"
│ └─ Pane 0 (npm run dev)
└─ Window 2 "shell"
└─ Pane 0 (interactive bash)
Output: (none — diagram only)
The prefix key
Every tmux keybinding starts with the prefix, which is Ctrl-b by default (Ctrl-a after the popular set -g prefix C-a rebind). Press the prefix, release it, then press the command key. Throughout this article a binding written as prefix d means "press Ctrl-b, release, then press d".
# Inside any shell — start a new session
tmux
# Press prefix d (Ctrl-b, then d) to detach
# The session keeps running in the background
Output (after detach):
[detached (from session 0)]
Sessions
A session is what makes tmux durable: detach with prefix d and the processes inside keep running. Use named sessions (tmux new -s name) so they're easy to find later, and tmux new -As name for idempotent attach-or-create.
# Create a new named session
tmux new -s work
# List sessions
tmux ls
# Output:
# work: 3 windows (created Sat May 24 10:00:00 2026)
# Attach to a named session
tmux attach -t work
# Attach-or-create (idempotent — won't fail if already exists)
tmux new -As work
# Kill a session
tmux kill-session -t work
# Kill everything
tmux kill-server
Output (tmux ls):
work: 3 windows (created Sat May 24 10:00:00 2026)
notes: 1 windows (created Sat May 24 09:14:22 2026)
Session keybindings
These all start with the prefix. The prefix s chooser is the fastest way to hop between sessions without leaving tmux.
| Binding | Action |
|---|---|
prefix d | Detach from session (leaves it running) |
prefix s | Interactive session chooser |
prefix $ | Rename current session |
prefix ( / prefix ) | Previous / next session |
prefix L | Switch to last session |
Windows
A window fills the visible screen and contains one or more panes. The default keybindings mirror a browser's tab semantics: prefix c creates a new window, prefix , renames, prefix n / prefix p cycles.
| Binding | Action |
|---|---|
prefix c | Create a new window |
prefix , | Rename current window |
prefix & | Kill current window (asks for confirmation) |
prefix n / prefix p | Next / previous window |
prefix 0 … prefix 9 | Jump to window by index |
prefix w | Interactive window chooser |
prefix . | Move window to another index |
prefix f | Find window by name |
# Create a session with two named windows from the start
tmux new -s work -n editor \; \
new-window -n server \; \
select-window -t editor
Output: (none — exits 0 on success)
Panes
A pane is a single shell occupying part of a window. Splits are either vertical (prefix %, creates a column boundary — panes side by side) or horizontal (prefix ", creates a row boundary — panes stacked). The mnemonic from the default key cap is that % looks vertical and " looks horizontal.
| Binding | Action |
|---|---|
prefix % | Split window vertically (panes side by side) |
prefix " | Split window horizontally (panes stacked) |
prefix ←/→/↑/↓ | Move to adjacent pane in that direction |
prefix o | Cycle to next pane |
prefix z | Toggle pane zoom (full screen) |
prefix x | Kill current pane |
prefix ! | Break pane out into its own window |
prefix q | Show pane numbers — press number to select |
prefix { / prefix } | Swap pane with previous / next |
prefix Space | Cycle through preset layouts |
prefix Ctrl-←/→/↑/↓ | Resize pane (one cell) |
prefix Alt-←/→/↑/↓ | Resize pane (five cells) |
# From inside a window — quick three-pane layout
# 1. Start in your shell
# 2. prefix % -> split vertically
# 3. prefix " -> split right pane horizontally
# Result:
# ┌────────┬────────┐
# │ │ │
# │ vim │ logs │
# │ ├────────┤
# │ │ server │
# └────────┴────────┘
Output: (none — interactive)
Idempotent attach-or-create
The single most-used invocation, especially in shell startup files: tmux new-session -As NAME attaches to a session called NAME if one exists, or creates one if not. Aliasing this lets you "enter the work session" with one short command from anywhere.
# Long form
tmux new-session -A -s work
# Compact form (same thing)
tmux new -As work
# Useful alias in ~/.bashrc
alias work='tmux new -As work'
alias notes='tmux new -As notes'
Output: (none — exits 0 on success)
If you SSH into a server and want every connection to drop straight into the same session, append this to the server-side
~/.bashrc:[[ -z "$TMUX" ]] && exec tmux new -As main. The$TMUXcheck prevents nested tmux when you reconnect.
Copy-mode
Copy-mode is tmux's pager — it freezes the pane, gives you scrollback navigation, and lets you select and yank text into a tmux paste-buffer. Enter with prefix [; leave with q. The motion keys depend on mode-keys: emacs (default) uses arrow/Page/Ctrl-keys; vi uses h/j/k/l/V/y.
# Enable vi-style keys (recommended)
# ~/.tmux.conf
setw -g mode-keys vi
Output: (none — config snippet)
vi mode binding | Action |
|---|---|
prefix [ | Enter copy-mode |
q | Leave copy-mode |
h j k l | Move cursor left/down/up/right |
Ctrl-u / Ctrl-d | Half-page up / down |
g / G | Top / bottom of scrollback |
/ then text + Enter | Search forward |
? then text + Enter | Search backward |
n / N | Repeat search forward / backward |
v | Start visual selection |
V | Linewise selection |
y | Yank selection to tmux buffer |
prefix ] | Paste most-recent buffer |
prefix = | Interactive buffer chooser |
To copy text from tmux into the system clipboard you need
xclip(X11),wl-copy(Wayland), orpbcopy(macOS), plus a tmux binding likebind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy". Without that step,yonly fills tmux's internal buffer.
Mouse support
set -g mouse on enables click-to-select-pane, scroll-wheel scrollback, and drag-to-resize pane borders. It does not disable normal terminal text selection — hold Shift while selecting to bypass tmux and let the terminal's selection take over (useful for copying out to the system clipboard).
# ~/.tmux.conf
set -g mouse on
Output: (none — config snippet)
Configuration
tmux reads its config file at startup and on every source-file. It checks two locations in order: the XDG path $XDG_CONFIG_HOME/tmux/tmux.conf (which defaults to ~/.config/tmux/tmux.conf when the variable isn't set) first, then the legacy ~/.tmux.conf. Pick one — having both is the most common silent-misconfiguration trap.
# Modern XDG location (preferred for new setups)
mkdir -p ~/.config/tmux
$EDITOR ~/.config/tmux/tmux.conf
# Legacy location (still works; what most older guides assume)
$EDITOR ~/.tmux.conf
# Print the config file tmux actually loaded
tmux show-options -gv default-shell # any show-options succeeds only after load
tmux info | head -20 # version, term, socket, config-file
Output (tmux -V):
tmux 3.5a
Reload without restarting (after editing): run tmux source-file ~/.config/tmux/tmux.conf from any shell, or — once you've added the bind r line in the minimal config below — press prefix r from inside tmux.
A minimal ~/.tmux.conf
A short config that fixes the most-complained-about defaults: rebind the prefix to Ctrl-a (easier to reach than Ctrl-b), enable vi keys and mouse, grow the scrollback, use 24-bit colour, and remap pane splits to keys that match what they do (| = vertical, - = horizontal).
# ~/.tmux.conf
# --- Prefix
unbind C-b
set -g prefix C-a
bind C-a send-prefix
# --- General
set -g mouse on
set -g history-limit 50000
set -g base-index 1 # windows start at 1
setw -g pane-base-index 1 # panes too
set -g renumber-windows on # close gaps when windows are killed
set -sg escape-time 10 # snappier Esc in vim
# --- True colour (24-bit)
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",xterm-256color:Tc"
# --- Vim-like copy-mode
setw -g mode-keys vi
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancel
# --- Intuitive splits (and open in current path)
unbind '"'
unbind %
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
# --- Vim-like pane navigation
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# --- Reload config
bind r source-file ~/.tmux.conf \; display-message "tmux.conf reloaded"
Output: (none — config file)
After editing, reload without restarting: press prefix r (with the binding above) or run tmux source-file ~/.tmux.conf from any shell.
Status bar customisation
The status bar at the bottom shows session, window list, and right-side widgets. status-left and status-right accept format strings that include variables like #S (session name), #W (window name), #H (hostname), and any shell command via #(cmd).
# ~/.tmux.conf — minimal status bar
set -g status-style 'bg=#1e1e2e fg=#cdd6f4'
set -g status-left '#[fg=#89b4fa,bold] #S '
set -g status-right '#[fg=#a6e3a1]#(whoami)@#H #[fg=#f9e2af]%Y-%m-%d %H:%M'
set -g status-interval 5
setw -g window-status-format ' #I:#W '
setw -g window-status-current-format '#[fg=#1e1e2e,bg=#89b4fa,bold] #I:#W '
Output: (none — config snippet)
Popups and menus
display-popup opens a centred floating window that runs any command and disappears when the command exits — perfect for a transient lazygit, htop, or nnn launcher without losing your underlying layout. display-menu builds a vertical menu of key → label → command triples, useful for grouping rarely-used bindings behind a single prefix key. Both have been polished across 3.4–3.6: -T titles, -B to keep the popup on close, -M to force-enable mouse inside a menu (3.6), and -x/-y accept format expansions (3.6).
# ~/.config/tmux/tmux.conf — popup launchers
bind g display-popup -E -w 90% -h 90% -T " lazygit " "lazygit"
bind T display-popup -E -w 80% -h 70% -d "#{pane_current_path}"
# Small actions menu (prefix m)
bind m display-menu -T "#[align=centre] Actions " -x C -y C \
"Reload config" r "source-file ~/.config/tmux/tmux.conf" \
"Rename window" n "command-prompt -I '#W' 'rename-window %%'" \
"Kill pane" k "kill-pane" \
"" \
"Close menu" q ""
Output: (none — config snippet)
Flags worth knowing for display-popup:
| Flag | Effect |
|---|---|
-E | Exit popup when the command exits |
-w 80% / -h 70% | Size as percentage of the client area |
-x C -y C | Centre on screen (numbers / formats also work) |
-T " title " | Border title (3.4+) |
-d <dir> | Start the command in <dir> (e.g. #{pane_current_path}) |
-B | Don't close on key — wait for the command to exit |
Hooks
A hook runs a tmux command whenever a named event fires — pane creation, window rename, client attach, layout change, and so on. Use hooks to enforce conventions (e.g. always renumber windows, auto-rename based on cwd) or wire integrations (e.g. notify on bell). In tmux 3.6 many session-scope hooks were split into pane and window scopes, which means the option you set-hook against has to match the event source.
# ~/.config/tmux/tmux.conf
# Rename window to current directory's basename whenever the pane changes path
set-hook -g pane-focus-in 'rename-window "#{b:pane_current_path}"'
# Run a notifier on every command error (3.6+)
set-hook -g command-error 'display-message "tmux: command failed"'
# Per-window hook (3.6+ scope change)
set-hook -w window-renamed 'display-message "renamed to #W"'
# Per-pane hook (3.6+ scope change)
set-hook -p pane-died 'display-message "pane #P died"'
Output: (none — config snippet)
The most useful event names: client-attached, client-detached, session-created, session-renamed, window-linked, window-renamed, window-layout-changed, pane-focus-in, pane-focus-out, pane-died, pane-mode-changed, and command-error (3.6+). Run tmux show-hooks -g to list the ones currently set.
Scripting tmux
Every interactive keybinding is also a CLI subcommand, so a fresh layout can be reconstructed by a script — handy for project-specific environments. Use tmux send-keys to type commands into a pane.
#!/usr/bin/env bash
# Open the "work" session with three windows pre-loaded
SESSION=work
tmux has-session -t "$SESSION" 2>/dev/null && {
tmux attach -t "$SESSION"
exit 0
}
tmux new-session -d -s "$SESSION" -n editor -c /home/alice/project
tmux send-keys -t "$SESSION:editor" 'vim .' C-m
tmux new-window -t "$SESSION:" -n server -c /home/alice/project
tmux send-keys -t "$SESSION:server" 'npm run dev' C-m
tmux new-window -t "$SESSION:" -n shell -c /home/alice/project
tmux select-window -t "$SESSION:editor"
tmux attach -t "$SESSION"
Output: (none — exits 0 on success)
Common pitfalls
- Prefix collisions with the shell or editor —
Ctrl-bis used by readline (move back one character);Ctrl-ais used by readline as "go to start of line". Many tmux users rebind toCtrl-SpaceorCtrl-qto avoid both. - Colours look wrong inside tmux — set
default-terminal "tmux-256color"and add aTcoverride interminal-overridesto pass 24-bit colour through. Escfeels laggy in vim —set -sg escape-time 10(down from default 500ms) fixes it.- Lost text selection — mouse mode steals the drag-selection gesture. Hold
Shift(orOptionon macOS) to bypass tmux and use the terminal's own selection. - Nested tmux — SSHing from one tmux session into another leaves you with two prefix keys to mash through. Use the
$TMUXenv var to detect nesting; some users bind a second prefix that only triggers when nested. - Pane numbering starts at 0 —
prefix 0is the first window. Setbase-index 1andpane-base-index 1if you prefer 1-indexed (matches the keyboard row). tmux kill-serverkills everything — including unsaved work in every session. Always preferkill-session -t NAMEunless you really mean it.
Real-world recipes
Persistent dev session that survives SSH disconnects
The canonical workflow: SSH in, attach (or create) the dev session, work in it. When the connection drops, processes keep running; reconnect and you're back exactly where you were.
# On the remote, in ~/.bashrc
if [[ -z "$TMUX" && -n "$SSH_CONNECTION" ]]; then
exec tmux new-session -A -s dev
fi
Output:
# After ssh alicedev@myhost
[work session attached]
Quick split-pane debugging layout
Three-pane "investigate this server" layout from one keystroke: editor on the left, server logs top-right, shell bottom-right.
tmux new-session -d -s debug -c /home/alice/app
tmux send-keys -t debug 'vim .' C-m
tmux split-window -h -t debug -c /home/alice/app
tmux send-keys -t debug 'journalctl -u myapp -f' C-m
tmux split-window -v -t debug -c /home/alice/app
tmux attach -t debug
Output: (none — exits 0 on success)
Synchronise input across panes
setw synchronize-panes on sends every keystroke to all panes in the current window — useful for running the same command on a row of SSH connections to a fleet of servers.
# In each pane, ssh to a different host
# Then in any pane:
# prefix :setw synchronize-panes on
# Type once, executed everywhere:
apt list --upgradable
# prefix :setw synchronize-panes off
# Back to normal
Output: (none — interactive)
Capture pane contents to a file
capture-pane dumps a pane's visible (or full-history) text to a tmux buffer, which can then be saved to a file. The cleanest way to grab the output of a long-running command after the fact.
# From any other pane
tmux capture-pane -pS -3000 -t debug:0.0 > /tmp/pane.log
Output:
$ npm run build
> build
> tsc && vite build
✓ built in 1.42s
Plugin management with tpm
The Tmux Plugin Manager (tpm) installs and updates plugins listed in tmux.conf. Popular plugins include tmux-resurrect (save/restore sessions across reboots) and tmux-continuum (auto-save every 15 min).
# Install tpm
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
Output: (none — exits 0 on success)
Then append the plugin list to ~/.tmux.conf:
# ~/.tmux.conf — append at end
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
set -g @continuum-restore 'on'
run '~/.tmux/plugins/tpm/tpm'
Output: (none — config snippet)
Inside tmux, install with prefix I (capital i), update with prefix U, uninstall with prefix Alt-u.
Other plugins worth knowing in 2026:
christoomey/vim-tmux-navigator— unifiesCtrl-h/j/k/lbetween vim/neovim and tmux panes; the navigation feels native.catppuccin/tmux— the most-popular themed status bar; pairs with Catppuccin terminal palettes.tmux-plugins/tmux-yank— bridges the tmux paste-buffer to the system clipboard automatically (no manualpbcopy/xclipbinding).tmux-plugins/tmux-fpp— opens any file path on the current pane in$EDITORwith one keystroke.
# Reload the config to load tpm itself
tmux source-file ~/.tmux.conf
Output:
TMUX environment reloaded.
Done, press ENTER to continue.
Cheat-card: most-used keys
A printable summary of the bindings to internalise first.
| Binding | Action |
|---|---|
prefix d | Detach (leave running) |
prefix c | New window |
prefix , | Rename window |
prefix n / prefix p | Next / previous window |
prefix 0…9 | Jump to window N |
prefix % | Vertical split |
prefix " | Horizontal split |
prefix arrow | Move between panes |
prefix z | Toggle pane zoom |
prefix x | Kill pane |
prefix [ | Copy-mode |
prefix ] | Paste buffer |
prefix : | Command prompt |
prefix ? | Show all bindings |
prefix ?opens an interactive list of every binding tmux knows — the fastest way to remember a key you've forgotten without leaving the session.
Sources
- tmux 3.5 release notes (GitHub) — extended-keys mode 2, mirrored
main-*layouts, copy-mode hyperlinks, mouse-handling fixes. - tmux
CHANGESfile (master) — authoritative log including 3.6 hook scope changes,command-error,display-popup -Mand-x/-yformat expansion. - Tmux 3.5 Released — linuxiac.com — readable overview of 3.5's user-facing changes.
- tmux XDG support — tmux/tmux#142 — history of
$XDG_CONFIG_HOME/tmux/tmux.confresolution. - Terminal Multiplexers: tmux vs Zellij (2026) — current comparison of philosophy, performance, and ecosystem.
- Zellij vs tmux — fosslinux.com (2026) — second 2026 comparison emphasising UX and floating panes.
- Tmux display-popup cheat sheet — justyn.io — practical
display-popuprecipes.