Configuration: Writing a .tmux.conf That Earns Its Keep
This chapter walks through a lean .tmux.conf, the options worth flipping, key bindings, rebinding the prefix, and hooks.
Where the Config Lives
~/.tmux.conf classic location
~/.config/tmux/tmux.conf XDG-friendly (tmux 3.1+)
Create it if it doesn't exist:
vim ~/.tmux.conf
Reload without restarting tmux:
<prefix> :source-file ~/.tmux.conf
Bind that to something easier:
bind r source-file ~/.tmux.conf \; display "reloaded"
Now <prefix> r reloads and shows a confirmation. Iterating on config is much faster.
A Starter .tmux.conf
Start here. Add to it as you hit pain.
# Prefix
unbind C-b
set -g prefix C-a
bind C-a send-prefix
# General
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",*256col*:Tc"
set -g history-limit 10000
set -g escape-time 10
set -g focus-events on
set -g mouse on
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
# Copy mode
setw -g mode-keys vi
set -g set-clipboard on
# Splits
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %
# Pane nav (vim-style)
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# Resize (repeatable)
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
bind r source-file ~/.tmux.conf \; display "reloaded"
# Status line
set -g status-style fg=colour250,bg=colour234
set -g status-left "#[fg=colour208,bold] #S "
set -g status-right "#[fg=colour244] %H:%M "
set -g status-left-length 30
setw -g window-status-current-style fg=colour16,bg=colour208,bold
Paste, save, reload. You have a setup most tmux users would recognise as sensible.
set vs setw vs set -g vs set -a
tmux options come in three scopes:
- Server options: affect the whole tmux server (one per user).
set -s - Session options: affect sessions.
setorset -g(g = global default) - Window options: affect windows.
setworset -wg
Most of the time you want set -g (global session) or setw -g (global window). The -g sets the default; specific sessions or windows can override.
set -s escape-time 10 server-level
set -g history-limit 10000 every session, unless overridden
setw -g mode-keys vi every window
The -a flag appends to an existing value instead of replacing:
set -g terminal-overrides ",*256col*:Tc"
set -ga terminal-overrides ",xterm-*:Tc"
Common for terminal settings.
Options Worth Knowing
Prefix
unbind C-b
set -g prefix C-a
bind C-a send-prefix
Ctrl-a is the classic rebind. Ctrl-space is another favourite. send-prefix lets you pass Ctrl-a through to the shell by pressing <prefix> <prefix>.
History
set -g history-limit 10000
Default is 2000, which you'll exhaust fast. 10k is a comfortable medium. Higher costs memory per pane.
Colour
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",*256col*:Tc"
Gets 256 colours and true-colour support. If your terminal emulator supports it, this flips it on.
If Vim's colours look wrong, this is almost always the fix.
Escape time
set -g escape-time 10
Default is 500ms, which makes Esc feel sluggish in vim. 10ms is snappy.
Base indices
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
Windows start at 1 instead of 0, matching the keyboard layout. renumber-windows on compacts indices when you close a window.
Mouse
set -g mouse on
Scroll-wheel scrolls, drags select, clicks focus. Try it for a week; either you love it or you don't.
Focus events
set -g focus-events on
Lets programs inside tmux (like vim's FocusGained autocommand) know when their pane is focused. Needed for some editor integrations.
Copy mode
setw -g mode-keys vi
set -g set-clipboard on
Vi bindings plus OSC 52 clipboard. See chapter 5 for more.
Key Bindings
The basic command:
bind key command
unbind key
Examples:
bind | split-window -h
bind - split-window -v
bind r source-file ~/.tmux.conf
Modifiers
bind -n key command no prefix needed (global key)
bind -r key command repeat: within repeat-time, skip prefix
bind -T copy-mode-vi key ... bind inside a specific key table
-n is powerful and dangerous. Use it for keys that don't conflict with anything else:
bind -n S-Up select-pane -U
bind -n S-Down select-pane -D
Now Shift+arrow moves between panes from anywhere, no prefix. Great. But if you had -n Up, you'd break arrow-key navigation in every program.
-r lets you press the key repeatedly without re-pressing prefix:
bind -r H resize-pane -L 5
<prefix> H H H H shrinks left by 20 cells.
Key-table bindings
In copy mode, bindings live in a separate table:
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancel
send-keys -X sends a named command inside copy mode. The above gives you vim-style visual selection followed by yank.
Hooks
Hooks run tmux commands when events happen. Examples:
set-hook -g session-created 'new-window -n shell'
set-hook -g client-attached 'refresh-client'
set-hook -g window-linked 'renumber-windows'
Useful for automating setup. Chapter 9 covers scripts that use hooks for rich session templates.
Environment Variables
tmux maintains its own environment for each session:
set -g update-environment "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY"
Default list covers SSH forwarding. Add anything you want propagated to new panes:
set -ga update-environment "DOCKER_HOST"
On <prefix> d and re-attach, new shells get updated values.
Plugin Manager
If you plan to use plugins, add the TPM lines (full details in chapter 10):
# plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-yank'
set -g @plugin 'tmux-plugins/tmux-resurrect'
# keep this line at the bottom
run '~/.tmux/plugins/tpm/tpm'
Requires TPM installed; see chapter 10.
Organising a Bigger Config
Once .tmux.conf gets past a hundred lines, split it:
source-file ~/.config/tmux/options.conf
source-file ~/.config/tmux/bindings.conf
source-file ~/.config/tmux/status.conf
source-file ~/.config/tmux/plugins.conf
Each file is just tmux commands. tmux sources them in order.
Portable Config
If you use tmux on multiple machines with different tmux versions:
if-shell '[ "$(tmux -V | cut -d" " -f2)" \> "3.1" ]' \
"set -g status-position top" ""
Clunky but functional. if-shell runs the first command if the shell expression returns truthy, else the second.
Alternatively, keep your config minimal and portable by default; put version-specific tweaks in a file you only source on specific machines:
if-shell '[ -f ~/.tmux.local.conf ]' 'source-file ~/.tmux.local.conf'
Common Pitfalls
"I changed a setting and it didn't take effect." Some options require a new session, not just a reload. <prefix> :kill-session and start over if a config change seems not to apply.
"My prefix rebind didn't stick." unbind C-b before set -g prefix, then bind the new key with send-prefix. Forgetting the unbind leaves both active, which is fine but confusing.
"Colours are wrong, even with default-terminal set." Check three things: your terminal emulator supports true colour, TERM inside tmux reports tmux-256color, and tput colors returns 256. If all three check out and it's still wrong, terminal-overrides needs to match your outer TERM.
"Reload doesn't reload bindings inside copy mode." Some bindings only apply when a new mode is entered. Leave and re-enter copy mode after changes to bind -T copy-mode-vi ....
"My config has stopped working on a server." Check the tmux version: tmux -V. Your set-hook or bind -N might be from a version newer than what's installed. Either upgrade tmux or guard the lines with if-shell.
Next Steps
Continue to 08-status-line.md to turn the bar at the bottom into something useful.