The most surprising thing about tmux configuration is that it’s almost entirely static, yet it can dynamically adapt to your environment in ways that feel like magic.

Let’s see it in action. Imagine you’re on macOS and you want your tmux prefix key to be Ctrl+a (a common choice for Emacs users), but on your Linux server, you prefer the default Ctrl+b. You also want to use a newer tmux feature, like set-option -s history-limit 10000, but only if your tmux version supports it. This is where conditional configuration comes in.

Here’s a snippet of a ~/.tmux.conf that handles this:

# Set default prefix to Ctrl+a on macOS, Ctrl+b on Linux
if-shell '[ "$(uname)" = "Darwin" ]' \
    'set-option -g prefix C-a' \
    'set-option -g prefix C-b'

# Set history limit only if tmux version is 2.0 or higher
if-shell '[ "$(tmux -V | cut -d. -f1)" -ge 2 ]' \
    'set-option -s history-limit 10000'

# Example: Bind a key differently based on OS
if-shell '[ "$(uname)" = "Darwin" ]' \
    'bind-key C-p display-message "Hello from macOS!"' \
    'bind-key C-p display-message "Hello from Linux!"'

Let’s break down the mental model. tmux configuration files are read once when tmux starts. The if-shell command is your gateway to dynamic behavior. It takes a shell command as its first argument. If that command exits with a status of 0 (success), the subsequent arguments (which are tmux commands) are executed. Otherwise, if the shell command exits with a non-zero status, the final argument (if provided) is executed.

The shell command [ "$(uname)" = "Darwin" ] checks if the output of uname is "Darwin" (which is what macOS reports). If it is, the first set-option -g prefix C-a is run. If not, the second set-option -g prefix C-b is run. This allows you to have OS-specific settings.

For version-based logic, we use tmux -V. tmux -V outputs something like tmux 3.2a. We pipe this to cut -d. -f1 to get just the major version number (e.g., 3). Then, [ "$(tmux -V | cut -d. -f1)" -ge 2 ] checks if this major version is greater than or equal to 2. If it is, set-option -s history-limit 10000 is executed. This ensures you don’t try to use a feature that doesn’t exist in older tmux versions, preventing errors.

The bind-key example shows how you can have entirely different keybindings based on the OS. This is incredibly powerful for tailoring your tmux experience to your specific workflow on different machines.

The if-shell command can take multiple conditional branches, but the common pattern is if-shell 'condition' 'command_if_true' 'command_if_false'. The command_if_false is optional; if omitted and the condition is false, nothing happens.

One aspect often overlooked is the interplay between if-shell and other tmux configuration directives. For instance, if you have a global set-option defined before an if-shell that might override it, the if-shell will win if its condition is met. However, if the if-shell is placed after a global setting, it needs to be a set-option command within the if-shell to effectively override it. The order of operations in your .tmux.conf matters, and if-shell provides a way to inject logic into that sequential execution.

The next step in mastering tmux configuration is understanding how to use if-shell to react to the presence or absence of specific files or directories, enabling even more granular environmental adaptation.

Want structured learning?

Take the full Tmux course →