Tmux for Persistent Dev Sessions — The Setup That Survives Reboots
You have six terminal tabs open: server, console, test watcher, logs, git, and one you’ve forgotten the purpose of. Your laptop restarts for an update and all six are gone, along with the console session that had the object graph you spent ten minutes building. Tmux fixes the second problem completely and the first one mostly, and the whole setup is about forty lines of config you write once.
The Model
Three levels, and the naming trips people up:
- Session — a workspace, usually one per project. Survives disconnection.
- Window — a tab within a session.
- Pane — a split within a window.
The server runs in the background, independent of any terminal. Close your terminal, the session keeps running. SSH drops, the session keeps running. That’s the whole value proposition, and everything else is ergonomics.
Example:
tmux new -s firstdev # create a named session
tmux ls # list sessions
tmux attach -t firstdev # reattach
tmux kill-session -t firstdev
Detach with Ctrl-b d. The session keeps going.
Remap the Prefix First
Ctrl-b is a genuinely bad default — it’s a two-hand stretch, and Ctrl-b is “back one character” in readline, which you use constantly.
Example:
# ~/.tmux.conf
unbind C-b
set -g prefix C-a
bind C-a send-prefix
Ctrl-a conflicts with “beginning of line” in readline, which is why bind C-a send-prefix exists — pressing it twice sends the real Ctrl-a through. Some people use Ctrl-Space instead; it conflicts with nothing.
A Config Worth Copying
Example:
# ~/.tmux.conf
# Prefix
unbind C-b
set -g prefix C-a
bind C-a send-prefix
# Sane defaults
set -g base-index 1 # windows start at 1, not 0
setw -g pane-base-index 1
set -g renumber-windows on # close window 2, window 3 becomes 2
set -g history-limit 50000
set -g mouse on
set -sg escape-time 0 # no delay on ESC — matters in vim
set -g focus-events on
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",*256col*:Tc"
# Splits that remember the current directory
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind c new-window -c "#{pane_current_path}"
# Vim-style pane navigation
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# Resize, repeatable (hold the key)
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5
# Reload config without restarting
bind r source-file ~/.tmux.conf \; display "Config reloaded"
# Vim-style 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-pipe-and-cancel "pbcopy"
Three of those punch above their weight:
escape-time 0 — the default 500ms delay makes vim feel broken inside tmux. This single line fixes the most common complaint people have about the combination.
-c "#{pane_current_path}" — new splits open in the directory you were in, not your home directory. Without it you retype cd ~/projects/whatever forty times a day.
renumber-windows on — keeps window numbers contiguous so prefix 3 always means the third window.
Scripting a Project Layout
The payoff. One command reconstructs your entire working environment.
Example:
#!/usr/bin/env bash
# ~/bin/dev-firstdev
SESSION="firstdev"
DIR="$HOME/projects/firstdev"
tmux has-session -t "$SESSION" 2>/dev/null && exec tmux attach -t "$SESSION"
tmux new-session -d -s "$SESSION" -c "$DIR" -n editor
tmux send-keys -t "$SESSION:editor" "nvim ." C-m
tmux new-window -t "$SESSION" -c "$DIR" -n server
tmux send-keys -t "$SESSION:server" "bundle exec jekyll serve --watch" C-m
tmux new-window -t "$SESSION" -c "$DIR" -n shell
tmux split-window -t "$SESSION:shell" -v -c "$DIR"
tmux send-keys -t "$SESSION:shell.2" "tail -f log/development.log" C-m
tmux select-pane -t "$SESSION:shell.1"
tmux select-window -t "$SESSION:editor"
exec tmux attach -t "$SESSION"
The has-session guard makes it idempotent — run it twice and you attach to the existing session rather than building a duplicate. That’s what makes it safe to alias:
alias dev="~/bin/dev-firstdev"
For declarative layouts, tmuxinator or tmuxp do the same thing from a YAML file. The shell script has no dependencies and is easier to debug, which is why it’s still what most people end up with.
Surviving Reboots
Tmux sessions survive terminal closure and SSH drops. They do not survive a machine restart — the server process dies with everything else. tmux-resurrect and tmux-continuum close that gap.
Example:
# ~/.tmux.conf
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
set -g @resurrect-capture-pane-contents 'on'
set -g @resurrect-processes 'ssh psql "~rails server" "~sidekiq"'
set -g @continuum-restore 'on'
set -g @continuum-save-interval '15'
run '~/.tmux/plugins/tpm/tpm'
continuum saves every fifteen minutes and restores on tmux start. @resurrect-processes lists which commands to relaunch — by default it restores the layout but not what was running in each pane, which is half the value.
Be deliberate about that process list. Auto-restarting a server is convenient; auto-restarting something that connects to production is not.
Copy Mode Without the Mouse
prefix [ enters copy mode. With mode-keys vi set, navigation is vim keys.
prefix [ enter copy mode
/ ? search forward / backward
v begin selection
y copy and exit
q exit
prefix ] paste
Searching the scrollback is the underrated part — prefix [ then /error jumps to the last occurrence of “error” in fifty thousand lines of log output, without piping anything anywhere.
Pro-Tip: Set up
tmux-continuumand then test the restore before you rely on it — reboot deliberately, on a Friday afternoon, and see what actually comes back. Almost everyone discovers the same two things: panes restore in the right layout but with the wrong working directory if the script that created them used relative paths, and any pane that was running an interactive process not in@resurrect-processescomes back as a bare shell. Both are five-minute fixes once you know, and both are extremely annoying to discover on a Monday morning when you needed the environment immediately. The restore is only as good as the one time you verified it.
Working With Others
Two people can attach to the same session and see the same thing — no screen-sharing software, no bandwidth, works over SSH on a bad connection.
# Both users attach to the same session
tmux attach -t pairing
# Attach read-only
tmux attach -t pairing -r
# Separate windows in a shared session
tmux new-session -t pairing -s my-view
That last one is the good trick: -t with a different -s creates a new session sharing the same windows, so each person can look at a different window independently while sharing the underlying processes.
Conclusion
Tmux earns its keep the first time your SSH connection drops during a migration and you reattach to find it still running. Remap the prefix, set escape-time 0 and pane_current_path on splits, and write one idempotent shell script per project so your whole environment is one command away. Add resurrect and continuum for reboot survival, then actually test the restore. The config is written once and the habits take about a week; after that, terminal tabs feel like a downgrade.
FAQs
Q1: Tmux or screen?
Tmux — actively maintained, better splitting, scriptable, sane config format. screen is still on every old server, which is the one reason to know it exists.
Q2: Does tmux work well with vim/neovim?
Yes, with escape-time 0 and correct terminal overrides for true colour. vim-tmux-navigator makes Ctrl-h/j/k/l move between vim splits and tmux panes with the same keys.
Q3: Why is my colour scheme wrong inside tmux?
Terminal capability mismatch. Set default-terminal "tmux-256color" and add the Tc override shown above, and make sure your outer terminal actually reports true colour support.
Q4: How do I rename a session or window?
prefix $ renames the session, prefix , renames the current window. Named windows make prefix w — the window picker — genuinely useful.
Q5: Does tmux use much memory?
The server is small; the scrollback buffer is what costs. history-limit 50000 across twenty panes adds up, so lower it if you’re running many sessions on a constrained box.
Check viewARU - Brand Newsletter!
Newsletter to DEVs by DEVs - boost your Personal Brand & career! 🚀