A Practical .tmux.conf: Settings That Actually Matter
Default tmux is already usable. You can create sessions, split panes, and detach without touching a single config line. That's worth remembering, because most .tmux.conf files you find online are two hundred lines of status-bar art and plugin declarations that solve problems the author had and you don't. A good config does one thing: it removes friction you actually hit. Everything else is maintenance you signed up for without noticing.
What follows is roughly twenty-five lines, no plugins required, with the reasoning for each one. The complete file is assembled at the end if you'd rather skip to it.
## Where the file lives and how to reload it
tmux reads ~/.tmux.conf when the server starts. Recent versions also read ~/.config/tmux/tmux.conf, which keeps your home directory tidy if you already use the XDG layout. Pick one. Having both is a debugging trap, because you will eventually spend twenty minutes editing the file tmux isn't reading.
"When the server starts" means when you open your first session, not every time you attach. Editing the file mid-session changes nothing until you tell tmux to re-read it: tmux source-file ~/.tmux.conf from a shell, or :source-file ~/.tmux.conf from the tmux command prompt. Bind it to a key and iterating on your config stops being annoying.
bind r source-file ~/.tmux.conf \; display-message "tmux.conf reloaded"// note: source-file applies what is in the file — it does not undo what isn't. Delete a bind line or remove an option and the old value stays live until the server restarts. When a config change stubbornly refuses to take effect, detach anything you care about and run tmux kill-server; that's the only way to be certain you're looking at a clean state.
## The prefix key
Every tmux binding is preceded by a prefix keystroke, Ctrl+b by default. The most common change people make is remapping it to Ctrl+a. Two reasons: GNU screen used Ctrl+a and a generation of muscle memory came with it, and Ctrl+a is simply an easier reach — especially on a keyboard where Caps Lock has been remapped to Ctrl, which puts the modifier directly beside the a.
unbind C-b
set -g prefix C-a
bind C-a send-prefixThe third line matters more than it looks. Ctrl+a is readline's beginning-of-line, used by bash, zsh, and most REPLs built on them. send-prefix forwards the literal keystroke when you press the prefix twice, so Ctrl+a Ctrl+a still jumps to the start of your command line. Leave it out and you lose that binding in every shell inside tmux.
There's a defensible case for leaving Ctrl+b alone: it's what every tutorial, every cheat sheet, and every colleague's machine assumes. If you regularly work on servers where your dotfiles aren't installed, the remap costs more than it saves. Either choice is fine. Pick one and stop revisiting it.
## Quality-of-life options
These take tmux from workable to comfortable. None of them are clever, which is the point.
set -g mouse on
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
set -sg escape-time 10
set -g history-limit 10000mouse on— click to focus a pane or window, drag borders to resize, scroll to enter copy mode. This one option replaced the four separate mouse settings older tmux versions had.base-index 1andpane-base-index 1— number windows and panes from 1 instead of 0 so they line up with the number row. Without it, window 0 sits past the9key and is a nuisance to reach.renumber-windows on— close window 2 of 4 and the rest shuffle down to fill the gap. Without it tmux leaves the hole and hands index 2 to the next window you create, so new windows appear in the middle of the status bar instead of at the end.escape-time 10— how many milliseconds tmux waits afterEscto see whether it's the start of an escape sequence. The default delay is long enough to feel like lag every time you leave insert mode in vim. Ten milliseconds is invisible to you and still enough for real sequences to arrive intact.history-limit 10000— scrollback lines kept per pane, up from a default of 2000. Raise it and you stop losing build output off the top; raise it far higher and you're paying real memory for every pane you open.
// note: base-index, pane-base-index, and history-limit only apply to things created after the option is set. Sourcing your config into a running session won't renumber existing windows or grow existing scrollback — new ones get the new value, old ones keep what they had. If a change looks like it did nothing, open a fresh window before concluding it's broken.
// note: With mouse mode on, dragging across a pane starts tmux's own selection instead of your terminal emulator's, so the usual drag-to-copy no longer reaches the system clipboard. Hold Shift while dragging to bypass tmux and use the terminal's native selection. That works in most terminals, but not all of them.
## Splits that make sense
The default split bindings are % for a left/right split and " for top/bottom. They're unmemorable, they need Shift, and the flags behind them are inverted from most people's intuition — split-window -h produces a side-by-side pair, not a stacked one. Bind characters that look like the split you want instead.
unbind '"'
unbind %
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind c new-window -c "#{pane_current_path}"| looks like a vertical divider and gives you side-by-side panes; - looks like a horizontal one and stacks them. The part worth stealing regardless of which keys you choose is -c "#{pane_current_path}". Without it, every new pane and window opens in whatever directory the session was originally started in. Four levels deep in a project tree, that's a cd you retype every single time you split.
tmux config files aren't parsed by a shell, but # still begins a comment and #{...} is a format expression. Keep format strings inside double quotes so tmux passes the whole value to the command rather than treating the rest of the line as a comment.
## Copy mode done right
Copy mode is tmux's scrollback viewer, and it has its own key table. By default that table is emacs-flavored, which is an odd fit if the rest of your setup is vi-flavored.
setw -g mode-keys vi
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi C-v send-keys -X rectangle-toggle
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancelmode-keys vi gives you / and ? for search, g and G for the top and bottom of the buffer, and vi motions in between. The three bindings then make selection behave the way vim trained you: v starts a selection, Ctrl+v toggles block selection, y yanks it and drops you back at the live prompt. The -T copy-mode-vi flag names the key table those bindings belong to — leave it off and you're rebinding v and y as prefix commands, which is not what you meant.
mode-keys governs copy mode only. The tmux command prompt, the one you open with prefix then :, follows a separate option called status-keys, so setting vi here won't make the prompt vi.
Yanking puts text into a tmux paste buffer, not your system clipboard. That is the single most common source of "why can't I paste this into my browser." There are two fixes. The portable one is to let tmux talk to the terminal over OSC 52:
set -g set-clipboard onThis survives SSH sessions and containers, because the terminal emulator at the other end does the actual clipboard write. It requires that your terminal supports OSC 52 and has it enabled — most modern ones do, a few need the feature turned on explicitly. The alternative is piping the selection into a local clipboard tool, which is reliable but tied to the machine:
# macOS
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"
# Linux / Wayland
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "wl-copy"
# Linux / X11
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xclip -selection clipboard -in"// note: Keep exactly one of those bindings — the last one loaded wins — and remember the command runs on the machine hosting the tmux server, not the one your keyboard is attached to. A config lifted from a macOS blog post fails silently on a Linux box: pbcopy doesn't exist, copy-pipe-and-cancel still exits copy mode as if it worked, and nothing ever reaches the clipboard.
## True color
If your colorscheme looks correct in a bare terminal and washed out or plainly wrong inside tmux, this is the reason. tmux advertises a terminal type to the programs running in its panes, and unless told otherwise that type doesn't claim 24-bit color. Vim, bat, and anything else with a theme quietly fall back to a 256-color approximation.
set -g default-terminal "tmux-256color"
set -sa terminal-overrides ",xterm-256color:RGB"The first line sets what tmux claims to be — the TERM value every pane inherits. The second tells tmux that the outer terminal, identified by your real TERM, handles true color. Replace xterm-256color with whatever echo $TERM prints outside tmux. The -a appends rather than replacing, so you don't wipe out other overrides, and -s is explicit about terminal-overrides being a server-level option.
If tmux-256color isn't in your system's terminfo database, tmux complains at startup or programs inside behave strangely. Check with infocmp tmux-256color; if it's missing, screen-256color is the widely available fallback, and the override line still gets you true color.
## The whole file
Everything above, assembled. This is a complete config with no external dependencies unless you uncomment a clipboard line.
# --- prefix ------------------------------------------------------
unbind C-b
set -g prefix C-a
bind C-a send-prefix # Ctrl+a twice sends a literal Ctrl+a
# --- general -----------------------------------------------------
set -g mouse on # click panes, drag borders, scroll
set -g base-index 1 # windows start at 1
setw -g pane-base-index 1 # panes start at 1
set -g renumber-windows on # no gaps after closing a window
set -sg escape-time 10 # no Esc lag in vim
set -g history-limit 10000 # scrollback lines per pane
# --- colors ------------------------------------------------------
set -g default-terminal "tmux-256color"
set -sa terminal-overrides ",xterm-256color:RGB" # match your outer $TERM
# --- splits ------------------------------------------------------
unbind '"'
unbind %
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind c new-window -c "#{pane_current_path}"
# --- copy mode ---------------------------------------------------
setw -g mode-keys vi
set -g set-clipboard on # OSC 52 clipboard via the terminal
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi C-v send-keys -X rectangle-toggle
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancel
# --- reload ------------------------------------------------------
bind r source-file ~/.tmux.conf \; display-message "tmux.conf reloaded"Save it, then run tmux kill-server once so nothing from a previous config lingers. After that, prefix + r is enough for every subsequent edit.
## Do you need a plugin manager?
tpm, the tmux plugin manager, is a script you clone plus a few lines in your config; plugins are git repos it fetches and sources for you. Nothing above needs it — every setting here is built into tmux. The one plugin that genuinely does something you can't hand-roll in a few lines is tmux-resurrect, usually paired with tmux-continuum to run automatically: it snapshots your sessions, windows, panes, and working directories to disk so a reboot doesn't cost you your layout. If you keep long-lived sessions and reboot regularly, that's a real problem solved. If you rebuild your workspace each morning from a shell script or a tmux new-session alias, you already have persistence you control, and adding a plugin manager is pure overhead.
The test for any line you're tempted to copy into this file is the same: name the friction it removes. If you can't, delete it and see whether you miss it.