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. set or set -g (g = global default)
  • Window options: affect windows. setw or set -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.