Dissecting tmux's options system: the four scope levels (server, session, window, pane), important options like history-limit and escape-time, and consistent environment and working directory management.

In episode 11 we covered keybindings — mapping commands to key combinations with bind-key and unbind-key so the most frequent actions are one keystroke away. But keys are only the entrance; what governs the behavior behind that door is options. In this episode we dissect tmux's options system thoroughly: the four scope levels, how to read and change them, the important options you must set, and the environment and working directory management that's often overlooked yet hugely determines workflow consistency.
In the real world, options are the difference between a tmux that merely "runs" and a tmux that "feels good". Two people can use the exact same tmux 3.7b, but their experiences are totally different just because one set history-limit and mouse on and the other didn't. Options are also the language engineers use to communicate: when a coworker says "set aggressive-resize on", you should immediately understand its effect on your machine.
The first distinction you must internalize: commands are actions, options are states. new-window is a command — it does something instantly. history-limit 10000 is an option — it changes how tmux behaves for the life of the server. Commands execute once; options persist and influence every operation afterward.
A fitting analogy is a car cabin. There are buttons that react immediately when pressed (commands), and there are switches that change the vehicle's base settings — seat position, pedal sensitivity, panel brightness (options). Switches don't produce an instantaneous action, but every subsequent action follows that setting. In tmux, you can create a new window anytime, but whether that window carries 2,000 or 10,000 lines of history is determined by the history-limit option set long before.
tmux divides options into four levels based on their scope of influence. Understanding these levels is key, because two options can have similar names but different behavior depending on the level they're set at — for example base-index at the session level governs window numbering, while pane-base-index at the window level governs pane numbering.
| Level | Scope | View | Change |
|---|---|---|---|
| Server | The whole server, all sessions | tmux show-options -s | tmux set-option -s |
| Session | One session, or all (-g) | tmux show-options -g | tmux set-option -g |
| Window | One window, or all (-g) | tmux show-window-options | tmux set-window-option -g |
| Pane | One pane, or all (-g) | tmux show-options -p | tmux set-option -p |
The rule of thumb: if you remember one thing, remember that an option set at a more specific level overrides the global value — just like a variable inside a function scope overrides the global variable. When debugging, you can't just look at global values; you must check the per-session, per-window, and per-pane values for the problematic target.
The commands to read options are show-options (with the scope flag) and the show-window-options alias for the window level. Without arguments, both print all options with their values; with an option name, only that option is printed.
tmux show-options -gFrom inside tmux, the same call can be done via the command prompt with prefix + : then typing the command without the tmux prefix. Here are the scope variants most used:
tmux show-options -s history-limit
tmux show-options -g mouse
tmux show-window-options -g aggressive-resize
tmux show-options -gp remain-on-exitNote the distinctive output form of these commands: one line containing option value, with an empty value for booleans that are off and quoted values for options containing spaces. This tidy format is no accident — in episode 14 we'll use show-options as a data source for scripting.
To change options, use set-option (alias set) and set-window-option (alias setw). The -g flag sets a global value so it applies to all sessions, windows, or panes now and in the future. Without -g, the change only applies to a specific target via -t.
set -g history-limit 10000
set -t dev status off
setw -g aggressive-resize on
setw -g pane-base-index 1The first line sets history capacity for the entire server, the second turns off the status bar only for the dev session, the third changes the resize behavior of all windows, and the fourth changes pane numbering in all windows. The set -g and setw -g patterns are the most common in ~/.tmux.conf, because a config file is meant to establish global values from server start.
Note
Some options only apply to newly created entities. history-limit, for example, doesn't change the history capacity of existing panes — it only applies to panes created afterward. If a change isn't visible, there are two possibilities: the config hasn't been reloaded, or the option only affects new objects.
tmux's default stores 2,000 lines of history per pane — often too little for reading migration logs or long build output. Community-common values range from 10,000 to 50,000. Because this option is server-wide and only applies to new panes, set it as early as possible in ~/.tmux.conf.
set -g history-limit 10000With mouse on, you can scroll history, select panes by clicking, drag borders to resize, and select text in copy mode. Many engineers disable it in certain editors, but as a global default, mouse on is the most common decision in production teams because it shortens the learning curve for new members.
By default, tmux resizes a window to fit the largest client. aggressive-resize on makes a window resize to follow the currently active client — important when one window is open in many sessions with different terminal sizes. The trade-off is clear: full-screen programs like vim and htop welcome it, but interactive programs slow to respond to SIGWINCH will feel rough.
default-terminal determines the terminal emulation used by programs inside the pane. The value tmux-256color (default in tmux 3.7b) already supports 256 colors; you can test by comparing tput colors output inside and outside tmux. Make sure the outer terminal also sets an appropriate TERM — otherwise colors will look broken or not appear at all.
escape-time is how many milliseconds tmux waits to distinguish a single Esc press from the start of an escape sequence like an arrow key. The 500 ms default makes Esc in editors like Vim feel heavy — press then wait a fraction of a second before the mode changes. Lowering it to 10 makes Vim's response feel instant.
set -g escape-time 10base-index changes window numbering from 0 to 1 — the majority preference. status on enables the status bar, which we'll later turn into a workspace information center when discussing format strings in advanced episodes.
set -g base-index 1
set -g status onBesides options, tmux stores environment variables for each session. This environment is a snapshot of the variables the client brought when attaching — and it's exactly what makes the experience different when you open a session from different machines.
The session environment is managed with set-environment (alias setenv). The most practical example: making sure EDITOR or an internal token is available in all panes of that session.
set-environment -g EDITOR nvim
set-environment -g MY_APP_ENV staging
show-environmentThe -g flag makes the variable global so new sessions inherit it. Conversely, update-environment is a list of variables synced from the client every time you attach — by default it includes DISPLAY, SSH_AUTH_SOCK, SSH_CONNECTION, and the like. This is why SSH agent forwarding keeps working inside tmux even as clients change: tmux overwrites those variable values from the newly attached client.
The working directory is the "home address" of each pane. By default, new-session and new-window use the client's working directory at the moment the command is run. To enforce a specific location — for example when an automation script creates the session — use the -c flag:
tmux new-session -d -s api -c /srv/api
tmux new-window -t api -n worker -c /srv/api/worker
tmux send-keys -t api:0 'pwd' EnterIn the api session, every pane knows exactly where it is in its project directory. This is what makes a tmux session superior to a manually opened terminal: location, environment, and layout are packed into one artifact that can be reopened.
One detail that often confuses: a new session created from inside tmux inherits the current session's environment, while a session created from outside uses the outer shell's environment. With set-environment -g, you guarantee certain variables always exist in all sessions regardless of where they were created.
set-environment -g DEPLOY_TARGET prodThe combination of set-environment -g and update-environment is two complementary directions: the first forces global values, the second syncs the client's "live" values. Understanding both will save you from the classic "why is the env different in that session?" confusion.
Here's a set of options that form a healthy starting point for almost any tmux 3.7b user:
set -g history-limit 10000
set -g escape-time 10
set -g default-terminal "tmux-256color"
set -g mouse on
set -g base-index 1
setw -g pane-base-index 1
setw -g aggressive-resize on
set -g status onReload with tmux source-file ~/.tmux.conf or prefix + r if you already bound the reload in episode 11, then test one by one. Don't copy blindly — each line has a trade-off, and the Common Pitfalls section below explains the traps that appear most often.
Setting a per-target option with -t then wondering why it isn't global. set -t dev status off only affects the dev session. If you meant all sessions, use set -g.
Lowering escape-time but the program in the pane is still slow. escape-time isn't the only source of latency — applications like Neovim have their own ttimeoutlen. Set both together for best results.
Expecting history-limit to change existing panes. This option only applies to new panes. After changing it, create a new window to test, don't scroll the old one.
Overwriting update-environment without including the default values. This list is a total replacement, not an addition. If you write set -g update-environment FOO, the variables DISPLAY and SSH_AUTH_SOCK stop being synced — unless that's the intention.
Setting default-terminal without adjusting the outer terminal. The values inside and outside tmux must be consistent; a mismatched TERM produces broken colors or odd characters in editors.
Forgetting to reload the config after changing options. The config is read once when the server is first created. Always run tmux source-file ~/.tmux.conf after editing, and make this a habit before blaming an option.
This episode gave you full control over tmux behavior: the four options scope levels, reading with show-options/show-window-options, changing with set-option/set-window-option, and key options like history-limit, mouse, aggressive-resize, default-terminal, escape-time, base-index, and status. You also now manage the environment via set-environment and update-environment, and control each pane's working directory with the -c flag.
Key points to take away:
set -g/setw -g are the config defaults; -t for specific targets.update-environment keeps client variables alive; set-environment -g forces global values.All these settings can still vanish the moment the server is shut down — which brings us to the next problem: preserving sessions along with all their state. In episode 13 we'll cover persistence, session restore, and data management — bringing sessions back to life after a reboot with tmux-resurrect and tmux-continuum, saving scrollback with capture-pane, and logging windows with pipe-pane. See you in episode 13!