# tmux Cheatsheet

- URL: https://karandeepsingh.ca/cheatsheets/terminal/tmux/
- Author: Karandeep Singh
- Published: 2025-07-02
- Tags: tmux, linux
- Summary: My tmux notes. Session management, window and pane keybindings, copy mode, config essentials, and scripting layouts with send-keys.

Half my job happens inside tmux: long-running deploys that survive dropped SSH connections, split panes tailing logs on three servers at once, a scripted dev layout that comes up with one command. These are the commands and keybindings I actually use, nothing more. Pair it with my [Bash CLI One-Liners Cheatsheet](https://karandeepsingh.ca/cheatsheets/bash/bash-cli/) for what to run inside those panes.

All keybindings below assume the default prefix `Ctrl-b` (written `C-b`). Press the prefix, release, then press the key.

_Diagram: Three levels, and almost every tmux confusion is mixing them up. **The session is the thing that survives** — it lives on the server, so closing your laptop or dropping SSH detaches you without killing anything. Windows are tabs inside it; panes are splits inside a window._

## Sessions

> **Docs:** [Getting Started on the tmux wiki](https://github.com/tmux/tmux/wiki/Getting-Started)

```bash
tmux new -s deploy            # new named session
tmux new -s deploy -d         # new session, detached (great in scripts)
tmux ls                       # list sessions
tmux attach -t deploy         # attach to a session by name
tmux attach -d -t deploy      # attach and detach any other client
tmux kill-session -t deploy   # kill one session
tmux kill-server              # kill everything
tmux rename-session -t 0 work # rename a session
```

| Keybinding | Action |
|------------|--------|
| `C-b d` | Detach from session (it keeps running) |
| `C-b s` | Interactive session picker |
| `C-b $` | Rename current session |
| `C-b (` / `C-b )` | Previous / next session |

The whole point: detach with `C-b d`, close your laptop, SSH back in later, `tmux attach -t deploy`, and your job is still running.

## Windows

> **Docs:** [tmux(1) on man.openbsd.org](https://man.openbsd.org/tmux)

Windows are like tabs inside a session.

| Keybinding | Action |
|------------|--------|
| `C-b c` | Create new window |
| `C-b ,` | Rename current window |
| `C-b n` | Next window |
| `C-b p` | Previous window |
| `C-b 0-9` | Jump to window by number |
| `C-b w` | Interactive window picker |
| `C-b &` | Kill current window (confirms) |
| `C-b .` | Move window to a new index |
| `C-b f` | Find window by name |

## Panes

> **Docs:** [tmux(1) on man.openbsd.org](https://man.openbsd.org/tmux)

Panes split a window into multiple terminals.

| Keybinding | Action |
|------------|--------|
| `C-b %` | Split vertically (side by side) |
| `C-b "` | Split horizontally (stacked) |
| `C-b o` | Cycle to next pane |
| `C-b ;` | Toggle to last-active pane |
| `C-b arrows` | Move to pane in that direction |
| `C-b z` | Zoom pane fullscreen (toggle) |
| `C-b x` | Kill current pane (confirms) |
| `C-b {` / `C-b }` | Swap pane left / right |
| `C-b !` | Break pane out into its own window |
| `C-b q` | Show pane numbers (press number to jump) |
| `C-b Space` | Cycle through preset layouts |

`C-b z` is the one to memorize. Zoom a pane to read logs full-screen, hit it again to drop back to the split.

## Resizing & Layouts

> **Docs:** [tmux(1) on man.openbsd.org](https://man.openbsd.org/tmux)

| Keybinding | Action |
|------------|--------|
| `C-b C-arrows` | Resize pane by 1 cell (hold prefix, tap arrow) |
| `C-b M-arrows` | Resize pane by 5 cells |
| `C-b M-1` … `M-5` | Apply preset layout (even-horizontal, even-vertical, main-horizontal, main-vertical, tiled) |

```bash
tmux resize-pane -D 10        # resize down 10 cells (also -U, -L, -R)
tmux select-layout tiled      # apply a layout from the command line
```

## Copy Mode & Scrollback

> **Docs:** [Getting Started on the tmux wiki](https://github.com/tmux/tmux/wiki/Getting-Started)

| Keybinding | Action |
|------------|--------|
| `C-b [` | Enter copy mode (scrollback) |
| `q` | Exit copy mode |
| `C-b ]` | Paste most recent buffer |
| `C-b PgUp` | Enter copy mode scrolled up one page |

With vi keys enabled (see config below), inside copy mode:

| Key | Action |
|-----|--------|
| `k` / `j`, `C-u` / `C-d` | Scroll up / down, half-page up / down |
| `g` / `G` | Top / bottom of scrollback |
| `/` then text | Search down (`?` searches up) |
| `n` / `N` | Next / previous search match |
| `Space` | Start selection |
| `Enter` (or `y`) | Copy selection and exit |

```bash
tmux show-buffer              # print last copied buffer
tmux list-buffers             # all paste buffers
tmux save-buffer /tmp/out.txt # dump buffer to a file
```

## Synchronize Panes

> **Docs:** [tmux(1) on man.openbsd.org](https://man.openbsd.org/tmux)

Type into every pane in the window at once. Handy when you have a handful of servers open in splits and want to run the same command on all of them.

```bash
# toggle on/off (prompt shows "synchronize-panes on")
C-b : setw synchronize-panes
```

**warning:**
Turn synchronize-panes **off** before doing anything destructive. It is easy to forget it is on and send `sudo systemctl restart` to four production hosts instead of one. Put the sync state in your status line so it is always visible.

## ~/.tmux.conf Essentials

> **Docs:** [tmux wiki](https://github.com/tmux/tmux/wiki)

```bash
# Remap prefix from C-b to C-a (easier to reach)
unbind C-b
set -g prefix C-a
bind C-a send-prefix

# Mouse support: click panes, drag borders, wheel scroll
set -g mouse on

# Start windows and panes at 1, not 0
set -g base-index 1
setw -g pane-base-index 1

# vi keys in copy mode
setw -g mode-keys vi
bind -T copy-mode-vi v send -X begin-selection
bind -T copy-mode-vi y send -X copy-selection-and-cancel

# Bigger scrollback, faster escape, sane colors
set -g history-limit 50000
set -sg escape-time 10
set -g default-terminal "tmux-256color"

# Renumber windows when one closes
set -g renumber-windows on

# Intuitive split keys that keep the current path
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"

# Status line: session name, window list, host + time
set -g status-style bg=black,fg=green
set -g status-left "[#S] "
set -g status-right "#h %H:%M"
```

Reload without restarting:

```bash
tmux source-file ~/.tmux.conf     # or: C-b : source-file ~/.tmux.conf
```

## Scripting tmux

Building a session from a script is the payoff: one command and the same
four panes every morning. Everything below was run end to end:

```text
$ tmux new-session -d -s deploy -n build
$ tmux new-window -t deploy -n logs
$ tmux split-window -t deploy:logs -h
$ tmux list-sessions
deploy: 2 windows (created Thu Oct 29 16:29:43 2026)
$ tmux list-windows -t deploy
0: build- (1 panes) [80x24] [layout b25d,80x24,0,0,0] @0
1: logs* (2 panes) [80x24] [layout 020a,80x24,0,0{40x24,0,0,1,39x24,41,0,2}] @1 (active)
$ tmux list-panes -t deploy:logs
0: [40x24] [history 0/2000, 960 bytes] %1
1: [39x24] [history 0/2000, 960 bytes] %2 (active)
# -d means it never attaches, so this runs fine from a script or a
# .bashrc. `tmux attach -t deploy` picks it up afterwards.
```

> **Docs:** [tmux(1) on man.openbsd.org](https://man.openbsd.org/tmux)

`send-keys` and `split-window` let you build a whole dev environment in one script:

```bash
#!/usr/bin/env bash
SESSION="dev"

tmux new-session -d -s "$SESSION" -n editor
tmux send-keys -t "$SESSION:editor" 'cd ~/project && vim .' C-m

tmux split-window -h -t "$SESSION:editor"
tmux send-keys -t "$SESSION:editor.1" 'cd ~/project && hugo server -D' C-m

tmux new-window -t "$SESSION" -n logs
tmux send-keys -t "$SESSION:logs" 'journalctl -f' C-m

tmux select-window -t "$SESSION:editor"
tmux attach -t "$SESSION"
```

Notes: `C-m` is Enter; targets are `session:window.pane`; `new-session -d` means the script works even when run outside tmux. Idempotent version: `tmux has-session -t dev 2>/dev/null || ./dev-env.sh`.

## Nested tmux (SSH Into a Server Running tmux)

> **Docs:** [tmux(1) on man.openbsd.org](https://man.openbsd.org/tmux)

When you run tmux locally and attach to a remote tmux over SSH, press the prefix **twice** to send it to the inner session: `C-b C-b c` creates a window on the remote. If you nest often, set the remote prefix to something else (e.g. `C-a`) so the two never collide.

## Most-Used Commands

> **Docs:** [tmux(1) on man.openbsd.org](https://man.openbsd.org/tmux)

| Command | What it does |
|---------|--------------|
| `tmux new -s name` | New named session |
| `tmux ls` | List sessions |
| `tmux attach -t name` | Attach to session |
| `tmux kill-session -t name` | Kill session |
| `C-b d` | Detach |
| `C-b c` / `C-b n` / `C-b p` | New / next / previous window |
| `C-b %` / `C-b "` | Vertical / horizontal split |
| `C-b z` | Zoom pane |
| `C-b [` | Copy mode / scrollback |
| `C-b : setw synchronize-panes` | Type into all panes |

Most of this pays off on remote boxes. See my [Ubuntu Terminal Cheatsheet](https://karandeepsingh.ca/cheatsheets/terminal/ubuntu-terminal/) for the server-side commands you'll be running inside those sessions.

**Question:** How long does it take you to rebuild your working layout after a disconnect? Could `tmux new-session -d` plus three `split-window` lines do it in one command?

## Related Cheatsheets

- [Bash CLI One-Liners](https://karandeepsingh.ca/cheatsheets/bash/bash-cli/): the find/grep/jq/rsync pipelines I end up typing inside these panes
- [Ubuntu Terminal](https://karandeepsingh.ca/cheatsheets/terminal/ubuntu-terminal/): apt, systemd, and journalctl on the servers these sessions are attached to
- [Amazon Linux 2 Terminal](https://karandeepsingh.ca/cheatsheets/terminal/al2-terminal/): the same idea for EC2, with yum, extras repos, SSM sessions, and instance-metadata queries

The rest of my terminal notes live in the [Terminal group](https://karandeepsingh.ca/cheatsheets/terminal/), and everything else is in the [cheatsheet library](https://karandeepsingh.ca/cheatsheets/).
