Eren's Tmux Configuration
Building a Tmux Status Bar That Actually Works
I spent way too long trying to get a good looking tmux status bar. Not “it kind of works” good looking, but the powerline segmented bar you see in screenshots on r/unixporn, with system stats, proper icons, and colors that don’t fall apart the second you reload your config. Along the way I ran into three separate problems that are barely documented anywhere. So here’s everything I learned.
What We’re Building
The final result is a powerline style status bar with colored segments that flow into each other using arrow separators. On the left you get your session name in a blue block. Your window tabs sit in the middle as individual segments, with the active one popping in cyan. On the right, four segments show CPU load, RAM usage, the date, and the time, each with its own icon and background color.
It looks clean. It looks modern. And every color actually renders.
The Three Traps Everyone Falls Into
Trap 1: Variables Don’t Work the Way You Think
The first thing you’ll try is defining color variables so you don’t have to repeat hex codes everywhere. Tmux gives you %hidden for this, and it looks perfect:
%hidden BLUE="#8898b4"
set -g status-style "fg=#{BLUE}"
This does not work. The %hidden keyword creates server environment variables, but #{BLUE} in a format string looks up tmux format variables (things like session_name or window_index). Your custom variable doesn’t exist in that namespace, so it resolves to an empty string. Your bar renders with no colors and you have no idea why.
The next thing you’ll try is user options with the @ prefix:
set -g @BLUE "#8898b4"
set -g status-left "#[fg=#{@BLUE}] hello"
This is closer. The #{@BLUE} format does resolve correctly in some contexts. If you test it with tmux display-message -p "#{@BLUE}" it prints the color value just fine. But it fails inside #[...] style directives. Tmux parses the style block before it expands format variables, so fg=#{@BLUE} becomes a literal string and your terminal has no idea what to do with it.
The fix is boring but reliable: hardcode every color. Put a comment block at the top of your theme section as a reference palette, and use the raw hex values everywhere. It’s ugly in the config file but it’s the only approach that actually works.
# Palette reference:
# bg=#1a1816 bg_light=#2e2a26 bg_hl=#3e3a36
# fg=#ddd5c8 fg_dim=#c4bcb0
# blue=#8898b4 cyan=#78a8a0 green=#88a878
set -g status-style "fg=#c4bcb0,bg=#1a1816"
Trap 2: Your Icons Are Probably Missing
If you’re copying config snippets from dotfile repos or blog posts, there’s a real chance the Nerd Font icon characters are silently getting stripped. This happens with certain text editors, clipboard managers, and even some file transfer tools. The config loads fine, tmux doesn’t complain, but your powerline arrows and icons just aren’t there. You see blank spaces where the arrows should be.
The way to catch this is to hex dump the relevant lines:
sed -n '119p' ~/.tmux.conf | od -A x -t x1z
If you see nothing but 20 (space) bytes where your icons should be, the characters got eaten. You’ll need to write them back using a tool that handles Unicode properly. Python works great for this since you can use explicit codepoints:
ARROW_R = '\ue0b0' # Powerline right arrow
ARROW_L = '\ue0b2' # Powerline left arrow
TERMINAL = '\uf120' # Terminal icon
Trap 3: Not All Nerd Font Icons Are Equal
Even with a Nerd Font installed, some icon ranges don’t render in every font variant. The safest icons are from the Font Awesome range (U+F000 through U+F2E0). These are included in every Nerd Font build. Icons from the Material Design range or the newer extensions are hit or miss depending on your font and version.
Stick to these and you’ll be fine:
| Icon | Codepoint | Description |
|---|---|---|
| U+F120 | Terminal | |
| U+F2DB | Microchip / CPU | |
| U+F1C0 | Database / RAM | |
| U+F073 | Calendar | |
| U+F017 | Clock | |
| U+F0E7 | Bolt / prefix |
Prerequisites
Before you start, you need two things.
A Nerd Font. Download one from nerdfonts.com and set it as your terminal’s font. I use UbuntuMono Nerd Font Mono. JetBrainsMono, FiraCode, and Hack are also popular choices. Make sure you pick the “Mono” variant for terminal use.
Tmux 3.2 or newer. You can check with tmux -V. Most of this config works on older versions too, but a few features like popup-border-lines need 3.2+.
The Status Bar Config
Here’s the full status bar section. Every color is hardcoded, every icon is from the safe Font Awesome range, and the powerline arrows create proper segmented transitions between each block.
# ── Status Bar ───────────────────────────────────────────────
set -g status on
set -g status-position bottom
set -g status-justify left
set -g status-style "fg=#c4bcb0,bg=#1a1816"
# Left: session name in a blue powerline block
set -g status-left-length 40
set -g status-left "#[fg=#1a1816,bg=#8898b4,bold] #S #[fg=#8898b4,bg=#1a1816] "
The left side is straightforward. Dark text on a blue background for the session name, with a powerline right arrow () transitioning back to the base dark background.
# Window tabs: inactive
setw -g window-status-format "#[fg=#2e2a26,bg=#1a1816]#[fg=#706860,bg=#2e2a26] #I #W #[fg=#2e2a26,bg=#1a1816]"
# Window tabs: active
setw -g window-status-current-format "#[fg=#78a8a0,bg=#1a1816]#[fg=#1a1816,bg=#78a8a0,bold] #I #W #[fg=#78a8a0,bg=#1a1816]"
setw -g window-status-separator " "
Each window tab is a self contained powerline segment. Inactive tabs get a dark, muted look. The active tab flips to a solid cyan background with dark text so it pops immediately. The left arrow () caps the left edge and the right arrow () caps the right edge, giving each tab that pointed segment shape.
# Right: powerline segments for load, ram, date, time
set -g status-right-length 120
set -g status-right "#{?client_prefix,#[fg=#e0ba78,bg=#1a1816]#[fg=#1a1816,bg=#e0ba78,bold] #[fg=#e0ba78,bg=#1a1816] ,}#[fg=#2e2a26,bg=#1a1816]#[fg=#88a878,bg=#2e2a26] #(cat /proc/loadavg | cut -d' ' -f1) #[fg=#3e3a36,bg=#2e2a26]#[fg=#78a8a0,bg=#3e3a36] #(free -h | awk '/Mem/{print $3\"/\"$2}') #[fg=#2e2a26,bg=#3e3a36]#[fg=#c4bcb0,bg=#2e2a26] %b %d #[fg=#8898b4,bg=#2e2a26]#[fg=#1a1816,bg=#8898b4,bold] %H:%M "
The right side is where it gets fun. Four segments flow into each other using left arrows () as transitions. The backgrounds alternate between two dark shades to create visual separation, and the final time segment uses the same blue as the session pill on the left, bookending the whole bar.
The system stats use simple shell commands inside #():
cat /proc/loadavg | cut -d' ' -f1grabs the 1 minute load averagefree -h | awk '/Mem/{print $3"/"$2}'shows used and total RAM
These update on every status-interval tick, which is set to 5 seconds in my config.
There’s also a conditional prefix indicator. When you press your prefix key, an orange bolt segment appears on the right. When you release it, the segment disappears. This is handled by the #{?client_prefix,...} conditional at the start of the status right string.
How Powerline Arrows Work
If the format strings look like hieroglyphics, here’s what’s going on. There are two special characters doing all the visual work:
The right arrow (U+E0B0) creates a triangle pointing right. You place it at the end of a segment. Set its foreground to the segment’s background color and its background to whatever comes next. This carves the right edge of the segment into a point.
The left arrow (U+E0B2) creates a triangle pointing left. You place it at the start of a segment. Same idea: foreground is the segment’s color, background is whatever was before it.
So a single floating segment looks like this:
#[fg=SEGMENT,bg=BASE] #[fg=TEXT,bg=SEGMENT] content #[fg=SEGMENT,bg=BASE]
^^^^ ^^^^
left entry right exit
And when two segments flow into each other, the arrow between them has the outgoing segment as its background and the incoming segment as its foreground:
#[fg=TEXT,bg=SEG_A] content #[fg=SEG_B,bg=SEG_A] #[fg=TEXT,bg=SEG_B] content
^^^^
transition arrow
Once you see the pattern, reading and modifying these strings becomes much easier.
The Full Color Palette
I built this around a warm, muted dark theme. Here’s the palette if you want to tweak it or adapt it to your own colors:
| Role | Hex | Usage |
|---|---|---|
| Background | #1a1816 |
Status bar base, pane bg |
| Background light | #2e2a26 |
Inactive segments |
| Background highlight | #3e3a36 |
Alternate segments |
| Foreground | #ddd5c8 |
Primary text |
| Foreground dim | #c4bcb0 |
Secondary text |
| Muted | #706860 |
Inactive window text |
| Blue | #8898b4 |
Session pill, time pill, borders |
| Cyan | #78a8a0 |
Active window, RAM stat |
| Green | #88a878 |
CPU/load stat |
| Orange | #e0ba78 |
Prefix indicator |
| Yellow | #d4a85c |
Activity alerts |
To adapt this to your own theme, replace the hex values in the status bar lines. Just remember: hardcode everything, don’t try to use variables.
Wrapping Up
The tmux status bar is one of those things that looks simple until you actually try to build one from scratch. The variable system is a trap, the Unicode handling is fragile, and the format string syntax takes some getting used to. But once you get past those bumps, you end up with something that’s genuinely useful. I glance at my status bar dozens of times a day now and it tells me exactly what I need to know: which session I’m in, what my windows are, and whether my machine is under load. All without opening htop.
If something isn’t rendering right, check the hex dump first. Nine times out of ten, the characters just aren’t in the file.