The real power behind the status bar: all of tmux's format variables, conditional computation expressions, and creating custom variables with set-environment for a status bar that truly comes alive.

In episode 9 we turned the status bar into a dashboard with simple variables like #{session_name} and #{host_short}. But that was only the surface. In this episode we enter the core of tmux's power that sets it apart from other multiplexers: format strings — a template language that lets you inspect, compute, and compose information dynamically. After this episode, you won't just "attach variables" anymore — you'll build expressions that adapt to circumstances.
Why does this matter? In the real world, useful information is almost always contextual. "Show the session name" is static; "show the session name, and highlight it red when a process errored" is dynamic and far more useful. Format strings enable things like that without writing an external program. This is also the basis of scripting (episode 14) — because display-message -p uses the same format engine.
tmux provides hundreds of format variables. All can be used inside a string with #{nama} syntax. Here are the ones most used in practice:
| Variable | Meaning | Example Value |
|---|---|---|
#{session_name} | Active session name | api |
#{session_windows} | Number of windows in the session | 3 |
#{window_index} | Active window number | 1 |
#{window_name} | Active window name | nvim |
#{pane_index} | Active pane number | 0 |
#{pane_current_path} | Pane directory path | /srv/api |
#{pane_current_command} | Command running in the pane | node |
#{pane_title} | Pane title | api-0 |
#{host} / #{host_short} | Host name / short host | devbox |
#{session_created_string} | Time the session was created | 2d ago |
#{pane_width} / #{pane_height} | Pane size | 120 |
#{client_width} / #{client_height} | Client size | 120 |
#{cursor_x} / #{cursor_y} | Cursor position | 0 |
The fastest way to see all available variables with their values:
tmux display-message -p '#{session_name}'
tmux display-message -p '#{pane_current_path}'
tmux display-message -p '#{pane_current_command}'
tmux display-message -p '#{window_index}:#{window_name}'display-message -p prints the formatted string to stdout without showing a popup — this is the bridge between the status bar and scripting. Whatever you write here, you can capture in the shell.
Note
The available variables depend on the evaluation context. In the status bar, the context is the active session. In window-status-format, the context is each window. In pane-border-format, the context is the pane. Variables irrelevant to the context produce an empty string.
The power of format strings lies in the computation operators. The syntax is #{<op>:<arg1>,<arg2>,...} — the operator followed by a colon, then arguments separated by commas. The most used operators:
| Operator | Function | Example |
|---|---|---|
#{==:a,b} | True if a == b | #{==:#{pane_current_command},nvim} |
#{!=:a,b} | True if a != b | #{!=:...#{...},nvim} |
#{||:...} | Logical OR | #{||:#{==:...#{...},vim},#{==:...#{...},nvim}} |
#{&&:...} | Logical AND | #{&&:a,b} |
#{m:regexp,text} | Regex match | #{m:node.*,...#{...}} |
#{e|...} | Evaluate expression | #{e|...} |
#{?:cond,then,else} | Ternary | #{?cond,ya,tidak} |
Boolean operators produce the string 1 (true) or 0 (false). To turn a boolean into text, use the ternary #{?:cond,true,false}.
A real example — showing an "EDITOR" indicator when the active pane runs an editor:
set -g status-right "#[fg=#f9e2af]#{?#{==:#{pane_current_command},nvim},NVIM,}"This line shows the text NVIM in the status bar only when the active pane's command is nvim; otherwise, the result is an empty string. Note that the ternary condition holds a boolean expression inside it — the #{?<bool>,<true>,<false>} pattern.
Format strings also read environment variables set with set-environment (alias setenv). This is the simplest way to make "your own variables".
tmux set-environment -g MY_TARGET staging
tmux display-message -p 'deploy target: #{MY_TARGET}'Because this variable is global (-g), its value is inherited by all sessions — and can be changed at any time. This is useful for configuration whose value changes per environment (dev/staging/prod) without editing the config file.
Tip
Combining set-environment -g with the #{==:...} expression enables status bar themes that change automatically: for example set-environment -g DEPLOY_TARGET prod and the status bar shows a red "PROD" label only when the target is prod. Without writing a single script line.
Format expressions can be stacked (nested) — conditions inside conditions. Example: showing a different indicator for editor vs dev server vs anything else:
set -g status-right "#[fg=#89b4fa]#{?#{==:#{pane_current_command},nvim},EDIT,}:#{?#{==:#{pane_current_command},node},SRV,}"The result: EDIT when an editor is active, SRV when node is active, empty otherwise. Even though it looks dense, each #{?...} block is independent and easy to understand if read block by block.
The same format engine is used elsewhere too:
window-status-format and window-status-current-format — show per-window info.pane-border-format (tmux 3.2+) — show info on the pane border.set -g pane-border-format "#[fg=#89b4fa] #{pane_index}:#{pane_current_path} "
set -g pane-border-status topWith pane-border-status top and pane-border-format, each pane shows its number and path at the top of the border — very helpful in multi-pane layouts.
Warning
Variables evaluated repeatedly (e.g. pane_current_command) add a small CPU load because tmux has to check the process status. On sessions with very many panes, using heavy variables across all panes at once can be felt. In episode 24 we'll discuss the balance between information richness and performance.
Wrong variable context. #{pane_index} inside window-status-format is meaningless because the context is a window, not a pane. Use variables relevant to the evaluation context.
Boolean isn't text. Operators like #{==:...} produce 1/0. To display text, wrap them in #{?:cond,true,false}.
Ternary syntax reversed. The order is #{?kondisi,nilai_true,nilai_false} — the wrong order produces confusing output.
Forgetting the curly braces around variables. #{session_name} is correct; session_name outside curly braces won't be replaced.
Overwriting a custom variable unknowingly. set-environment -g MY_VAR overwrites the previous value. Make sure the variable name doesn't collide with tmux's internal variables (uppercase is generally safe).
Testing with display-message without -p. tmux display-message '#{...}' shows a popup on screen; -p prints to stdout — use -p when you want to capture output in the shell.
This episode opened tmux's format string engine in full: the main variable catalog, conditional computation operators (#{==:}, #{||:}, #{&&:}, #{m:}, #{?:}), how to add custom variables with set-environment -g, nested expression techniques, and applying formats to window status and pane borders.
Key points to take away:
#{?:cond,then,else} turns booleans into text.set-environment -g creates custom variables changeable at runtime.The ability to "read and display" information pairs perfectly with the ability to "command and automate". In episode 11 we cover custom keybindings, command mode & menus — mapping commands to keys, using display-menu and display-popup for quick interfaces, and controlling tmux from the command prompt. See you in episode 11!