tmux 3.6a: Scripted Sessions, Plugins, and Persistence

Tmux handles pane splitting and window management well out of the box, but most people stop there. The real gains come from treating tmux as infrastructure. You script your session layouts so one command rebuilds your whole dev environment. You keep sessions alive across reboots so you never lose context. You add plugins for clipboard sync, fuzzy finding, and pattern matching. With tmux 3.6a and a few good plugins, your terminal becomes a persistent, scriptable IDE rather than a simple multiplexer.
This guide covers the workflows and config that separate casual tmux users from people who build their whole workday around it.
Scripted Session Layouts: Reproducible Workspaces in One Command
Opening tmux, making splits by hand, moving to the right directories, and starting services gets tedious when you do it many times a day. A scripted session layout cuts out that ceremony.
The core idea is simple. You write a shell script that calls tmux commands to build your exact window and pane arrangement. The script then runs whatever commands belong in each pane. Here is a practical example for a web dev project:
#!/bin/bash
SESSION="webapp"
# Attach if session already exists
tmux has-session -t $SESSION 2>/dev/null && tmux attach -t $SESSION && exit
# Create new session with first window named "editor"
tmux new-session -d -s $SESSION -n "editor"
tmux send-keys -t $SESSION:editor "nvim ." C-m
# Window 2: server logs
tmux new-window -t $SESSION -n "server"
tmux send-keys -t $SESSION:server "npm run dev" C-m
tmux split-window -v -t $SESSION:server
tmux send-keys -t $SESSION:server.1 "docker compose logs -f" C-m
# Window 3: git
tmux new-window -t $SESSION -n "git"
tmux send-keys -t $SESSION:git "lazygit" C-m
# Select the editor window and attach
tmux select-window -t $SESSION:editor
tmux attach -t $SESSIONThe tmux has-session check at the top makes the script idempotent. Run it again and it attaches to the existing session instead of making a duplicate. The -c flag on split-window and new-window can also set the working directory. That helps when different panes need to work in different subdirectories of a monorepo.
The key commands to remember:
| Command | Purpose |
|---|---|
tmux new-session -d -s name | Create a detached session |
tmux new-window -t session -n name | Add a named window |
tmux split-window -h / -v | Horizontal / vertical split |
tmux send-keys -t session:win.pane "cmd" C-m | Type and execute a command in a specific pane |
tmux select-layout even-vertical | Apply an automatic layout |
Tmuxinator and Tmuxp as Alternatives
If keeping shell scripts feels brittle, tmuxinator
and tmuxp
let you define the same layouts in YAML. Tmuxinator is Ruby-based (gem install tmuxinator). Tmuxp is Python-based (pip install tmuxp). Both generate the underlying tmux commands for you.
A tmuxp configuration for the same layout:
session_name: webapp
windows:
- window_name: editor
panes:
- nvim .
- window_name: server
layout: even-vertical
panes:
- npm run dev
- docker compose logs -f
- window_name: git
panes:
- lazygitSave this to ~/.config/tmuxp/webapp.yaml and run tmuxp load webapp. The YAML approach makes layouts easier to version control alongside your project
. Tmuxp also supports variables, so you can parameterize paths and project names.
Session Persistence with tmux-resurrect and tmux-continuum
By default, all tmux sessions disappear when the tmux server stops. That happens on every reboot, every crash, or any time you run tmux kill-server by accident. For long-running dev environments with dozens of panes and specific commands in each, losing that state is a real setback.
tmux-resurrect fixes this by saving and restoring the whole tmux environment. tmux-continuum builds on top of it. It runs the save and restore cycle for you, so you never have to think about it.
Setting Up Resurrect and Continuum
Both plugins install through TPM (covered in the next section). Add these lines to your tmux.conf:
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
# Auto-save every 15 minutes
set -g @continuum-save-interval '15'
# Auto-restore when tmux server starts
set -g @continuum-restore 'on'Press prefix + I inside tmux to install them. After that, prefix + Ctrl-s saves the environment by hand, and prefix + Ctrl-r restores it. The save files live in ~/.local/share/tmux/resurrect/.
What Gets Restored
Tmux-resurrect captures session names, window names, pane layouts and geometry, the working directory of each pane, and the running program (if it sits on the restorable programs list). By default, it restores only a whitelist of safe-to-restart programs: vim, nvim, man, less, top, and htop.
You can extend this list for your own workflows:
set -g @resurrect-processes 'nvim lazygit "npm run dev" "docker compose up"'Use the ~ prefix for exact command matching when you need to tell similar commands apart:
set -g @resurrect-processes '"~npm run dev" "~npm run build"'Pairing with Neovim Session Restore
If you use Neovim, add this setting so tmux-resurrect triggers Neovim’s own session save/restore:
set -g @resurrect-strategy-nvim 'session'This needs a Neovim session plugin like auto-session or persistence.nvim to handle Neovim’s side of the handshake. The result: a reboot restores not just your tmux panes but also your open Neovim buffers, cursor positions, and splits within each pane.
TPM and Essential Plugins
TPM (Tmux Plugin Manager) brings package management to tmux. Without it, installing plugins means cloning repos and sourcing scripts by hand. With it, you declare plugins in your config file and press a key combination.
Installing TPM
git clone https://github.com/tmux-plugins/tpm ~/.config/tmux/plugins/tpmAdd this to the very bottom of your tmux.conf:
# Initialize TPM (keep this line at the bottom)
run '~/.config/tmux/plugins/tpm/tpm'Reload your config with tmux source ~/.config/tmux/tmux.conf. Then press prefix + I (capital I) to install any declared plugins. prefix + U updates them, and prefix + alt + u removes plugins you have deleted from the config.
TPM needs tmux 1.9 or higher, git, and bash. The current stable is 3.6a, so compatibility is not a concern on any modern system.
Plugins Worth Installing
Start with tmux-sensible (tmux-plugins/tmux-sensible). It sets sane defaults that cut 20+ lines of boilerplate config: UTF-8 support, 50,000-line scrollback, faster escape-time (which Neovim users need, since they otherwise hit a delay when pressing Escape), and focus-events on for terminal apps that track focus.
For clipboard sync, tmux-yank (tmux-plugins/tmux-yank) connects tmux’s internal clipboard to your system clipboard. It detects your platform and uses wl-copy on Wayland, xclip on X11, or pbcopy on macOS. In copy mode, y copies the selection to the system clipboard. Outside copy mode, prefix + y copies the current command line.
The tmux-fzf-url plugin (wfxr/tmux-fzf-url) scans the visible pane content for URLs and shows them in an fzf
selector. Press prefix + u and pick a URL to open it in your browser via xdg-open. It is handy when you review log output with links to dashboards, CI pipelines, or error tracking pages.
Finally, tmux-thumbs (fcsonline/tmux-thumbs) highlights copyable patterns in the visible pane: IP addresses, file paths, git hashes, UUIDs, hex strings. It assigns single-key hints to each match, much like Vimium in a web browser. Press prefix + Space, see the hints overlay, press a key, and the matched text is copied. It is written in Rust, so the overlay renders fast even with dense output.

| Plugin | Purpose | Key Binding |
|---|---|---|
| tmux-sensible | Sane defaults | N/A (automatic) |
| tmux-yank | System clipboard | y in copy mode |
| tmux-fzf-url | Open URLs from pane | prefix + u |
| tmux-thumbs | Copy patterns with hints | prefix + Space |
| tmux-resurrect | Save/restore sessions | prefix + Ctrl-s / Ctrl-r |
| tmux-continuum | Auto-save sessions | Automatic |
Advanced tmux.conf: Keybindings, Status Bar, and Nesting
Stock tmux is usable, but a few targeted config changes make a clear difference over a full workday.
Prefix Key
The default Ctrl-b prefix is awkward to reach. Two popular alternatives:
# Screen-style prefix
set -g prefix C-a
unbind C-b
bind C-a send-prefix
# Ergonomic alternative that avoids shell conflicts
set -g prefix C-Space
unbind C-b
bind C-Space send-prefixVi-Style Copy Mode
If you already think in vim motions, this makes copy mode feel natural:
setw -g mode-keys vi
bind -T copy-mode-vi v send -X begin-selection
bind -T copy-mode-vi y send -X copy-pipe-and-cancel "wl-copy"Replace wl-copy with xclip -selection clipboard on X11 or pbcopy on macOS.
Intuitive Pane Splitting
The default % and " bindings for splits are hard to recall. Visual mnemonics work better:
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"The -c "#{pane_current_path}" flag makes new panes open in the same directory as the pane you split from, rather than defaulting to your home directory.
Seamless Vim/Tmux Navigation
vim-tmux-navigator
lets you use Ctrl-h/j/k/l to move between Neovim splits and tmux panes without switching mental models. Add it to your tmux.conf and install the matching Neovim plugin. Then you can move between editor splits and terminal panes with the same keys.
Status Bar Customization
The status bar takes up one line but carries a lot of useful info. Here is a minimal config that covers the essentials:
set -g status-style "bg=#1a1b26 fg=#c0caf5"
set -g status-right "#{?client_prefix,#[bg=red] PREFIX ,} %H:%M %d-%b"
set -g status-interval 5The #{?client_prefix,...} conditional shows a bright red PREFIX indicator when you press the prefix key. That helps when you are learning new bindings or debugging key conflicts.
Nested Tmux for SSH Sessions
When you SSH into a remote server running its own tmux instance, every prefix key goes to your local tmux. The standard solution uses F12 as a toggle:
bind -T root F12 set prefix None \; set key-table off \; set status-style "bg=#4a0000"
bind -T off F12 set -u prefix \; set -u key-table \; set -u status-stylePress F12 to turn off local tmux keybindings and turn the status bar red. The red bar reminds you that keystrokes now go to the remote tmux. Press F12 again to turn local bindings back on.
Performance Tuning and Memory
Tmux’s default scrollback buffer is 2,000 lines per pane. Raising it to 50,000 lines (what tmux-sensible sets) is a fair middle ground. Going much higher, say 200,000 lines or more, will use a lot more memory if you keep many panes open. Each line in the buffer uses memory, and tmux can get sluggish as the buffer fills.
Key performance settings:
# Scrollback - balance between usefulness and memory
set -g history-limit 50000
# Eliminate escape delay (critical for Neovim)
set -sg escape-time 0
# Faster status bar updates
set -g status-interval 5
# Enable focus events for terminal apps
set -g focus-events onThe escape-time setting deserves a close look. After an Escape keypress, tmux waits this many milliseconds before it decides whether the key is a standalone Escape or the start of a terminal escape sequence. The default of 500ms causes a half-second delay when you switch modes in Neovim. Setting it to 0 fixes that, but it can sometimes cause issues with certain terminal emulators
. Try 10ms if 0 causes problems.
Real-World Workflow Patterns
Individual features are useful on their own, but they work best when combined into consistent daily patterns.
Project-Per-Session
Keep one tmux session per project, named after the project: tmux new -s blog, tmux new -s api, tmux new -s infra. Switch between them with prefix + s (an interactive session list with preview) or with prefix + ( and prefix + ) for previous and next session. Paired with tmux-continuum, these sessions persist for as long as you want. You can keep a dozen projects suspended and ready to resume at any time.
Popup Terminals
Tmux 3.3+ supports floating popup windows that overlay your current workspace:
bind p display-popup -E -w 80% -h 80% "lazygit"
bind g display-popup -E -w 80% -h 80% "btop"Press your binding, the popup appears, do your work, and press q (or the tool’s exit key) to dismiss it. This works well for tools you check briefly without disturbing your pane layout: git status, system monitoring, a quick shell calculation, or a scratchpad terminal.
Synchronized Pane Input
Toggle synchronized input to type in all panes at once:
bind e setw synchronize-panesThis is great for multi-server admin. SSH into four servers in four panes, press prefix + e, and every command you type runs on all four at once. Press prefix + e again to turn it off.
Tmux Hooks for Automation
Tmux hooks let you trigger actions on specific events. A few practical examples:
# Show status bar only when multiple windows exist
set-hook -g after-new-window 'if "[ #{session_windows} -gt 1 ]" "set status on"'
set-hook -g window-closed 'if "[ #{session_windows} -lt 2 ]" "set status off"'
# Notify when a session closes
set-hook -g session-closed 'run-shell "notify-send \"tmux\" \"Session closed: #{session_name}\""'Running Tmux as a Systemd Service
For always-on tmux sessions that start at boot without requiring a login, create a systemd user service
at ~/.config/systemd/user/tmux.service:
[Unit]
Description=tmux default session
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/tmux new-session -d -s main
ExecStop=/usr/bin/tmux kill-server
[Install]
WantedBy=default.targetEnable it with systemctl --user enable tmux.service and loginctl enable-linger $USER, so the user session starts at boot, not just at login. Paired with tmux-continuum’s auto-restore, your sessions come back fully populated after a reboot with no manual steps.
How Does Tmux Compare to Zellij?
Zellij is the best-known modern alternative to tmux. It is written in Rust with a focus on ease of use.

A brief comparison:
| Feature | tmux | Zellij |
|---|---|---|
| Language | C | Rust |
| Plugin system | Shell scripts via TPM | WebAssembly (WASI) |
| Configuration | tmux.conf (custom syntax) | KDL format |
| Learning curve | Steeper, relies on documentation | Built-in toolbar shows shortcuts |
| Memory usage | ~5-10 MB | ~22 MB |
| Session persistence | Via tmux-resurrect plugin | Built-in (partial) |
| Remote sessions | Native | Added in v0.44 |
| Ecosystem maturity | 17+ years, massive plugin library | Younger, growing quickly |
Zellij is worth a look if you are starting fresh and value discoverability. Its mode-based interface with a dynamic toolbar cuts the need for cheat sheets. Tmux stays the stronger choice if you need deep scripting, a proven plugin ecosystem, or support on every server you will ever SSH into.
Putting It All Together
A complete, production-ready tmux.conf that pulls in everything here would include TPM setup, tmux-sensible as a base, tmux-resurrect and tmux-continuum for persistence, tmux-yank for clipboard, and vim-tmux-navigator for smooth pane movement. It would also add a custom prefix key, vi copy mode bindings, intuitive split bindings, a status bar with a prefix indicator, and F12 nesting support. That is roughly 30 to 40 lines of config that changes how your terminal works in practice.
Start with the session scripting and persistence setup. Those two changes alone save more time than any other tmux tweak. Add plugins one at a time as you hit friction in your daily work. The goal is not to configure everything at once. It is to build a setup that adapts to your workflow over time.
Botmonster Tech