Dev In The Mountain Header
A Developer In The mountains having fun

Zellij — why I switched from tmux

What is Zellij?

Zellij is a modern terminal multiplexer written in Rust. Like tmux and screen before it, it lets you split your terminal into panes, organize work into tabs, and keep sessions running in the background so you can detach and reattach whenever you want — from your local machine or over SSH. Where it differs is in what it does out of the box and how it's put together under the hood.

I used tmux for years. It's rock solid and it's everywhere, but I finally moved my daily driver over to Zellij. Here's why.

Why I switched from tmux

Sane defaults, no config required

The single biggest reason: Zellij is genuinely useful the moment you install it. tmux ships with a bare, almost hostile default configuration — no visible status bar worth looking at, a prefix key workflow you have to memorize before anything feels usable, and pane borders you can barely see. Getting tmux into a state I actually liked meant hundreds of lines of .tmux.conf, several plugins, and a plugin manager (tpm) just to bootstrap it all.

Zellij gives you a discoverable UI on first launch — an on-screen status bar showing you the active keybindings for whatever mode you're in, sensible pane/tab management, and floating panes — with zero configuration. New users can actually learn it by reading the screen instead of memorizing a cheat sheet first.

Discoverable, modal keybindings

Zellij borrows a modal approach (loosely similar to Vim): you enter a mode — Pane, Tab, Resize, Move, Scroll, Session — and the bottom bar shows exactly what keys do what in that mode. tmux's single-prefix-plus-mnemonic model works fine once memorized, but it isn't self-documenting. I no longer need a cheat sheet taped to my mental model just to remember whether it's % or " for a vertical split.

Layouts as code, and they're simple

Both tools support saving/restoring layouts, but Zellij's KDL-based layout files are easier to read and write than tmux's scripted tmuxinator/shell-script approach. I can define a whole multi-pane, multi-tab project layout in one small, human-readable file and drop it in a repo alongside the project it belongs to.

Floating panes

Zellij has floating panes built in — a quick scratch pane you can pop up over your current layout for a one-off command, without disturbing your pane arrangement underneath. tmux has no real equivalent without external tooling. I love the floating panes both look at function for doing something quick that I'm going dismis in a few moments.

Written in Rust, sane crash behavior

Zellij is written in Rust and it shows in day-to-day robustness — I have had far fewer weird rendering glitches or hangs than I occasionally hit with tmux over SSH on flaky connections. It's a smaller thing, but reliability compounds when a multiplexer is the thing everything else in your terminal lives inside of.

It's still not perfect

To be fair to tmux: it has a much longer track record, a much larger plugin ecosystem, and is preinstalled or trivially available on essentially every server you'll ever SSH into. Zellij's plugin system (WASM-based) is younger and smaller, and every once in a while I still reach for a tmux-only trick out of old habit. But for my day-to-day local workflow, Zellij's out-of-the-box experience and cleaner mental model won out partly because it just works well on every system i have installed it on without a bunch of tinkering.

Getting started

# install (see https://zellij.dev/documentation/installation for all options)
cargo install --locked zellij

# just run it
zellij

# attach to (or create) a named session
zellij attach -c mysession

Often used commands

From the shell

CommandWhat it does
zellijstart a new session
zellij -s namestart a new session with a name
zellij attach -c name (zellij a -c name)attach to a session, create it if it doesn't exist
zellij lslist sessions
zellij kill-session name (zellij k name)kill a session
zellij delete-session name (zellij d name)delete an exited (resurrectable) session
zellij --layout namestart with a layout
zellij run -- htopopen a command in a new pane from inside zellij
zellij edit file.txtopen a file in your $EDITOR in a new pane

Inside Zellij (default keybindings)

You don't have to memorize these, the bar at the bottom shows them, but these are the ones I use the most.

KeysWhat it does
Alt nnew pane
Alt h/j/k/l (or arrows)move focus between panes (and tabs at the edges)
Alt ftoggle floating panes
Alt + / Alt -resize the current pane
Alt [ / Alt ]cycle swap layouts
Ctrl p then d / rPane mode -- new pane down / right
Ctrl p then xclose pane
Ctrl p then ftoggle fullscreen for the pane
Ctrl p then w / etoggle floating panes / float or embed the current pane
Ctrl p then crename pane
Ctrl t then n / xTab mode -- new tab / close tab
Ctrl t then rrename tab
Ctrl t then h / l or 1-9previous / next tab, or jump to tab
Ctrl t then bbreak the current pane out into its own tab
Ctrl n then h/j/k/lResize mode
Ctrl h then h/j/k/lMove mode -- move the pane around
Ctrl s then j/k, d/uScroll mode -- scroll, half page down/up
Ctrl s then ssearch the scrollback
Ctrl s then eopen the scrollback in your $EDITOR
Ctrl o then dSession mode -- detach
Ctrl o then wsession manager (switch, create, resurrect sessions)
Ctrl o then cconfiguration screen
Ctrl glock mode -- pass all keys through to the app (handy in NeoVIM)
Ctrl qquit zellij
Esc / Enterback to normal mode

tip: if the Ctrl keys clash with your apps, Zellij also has an "unlock-first" preset (pick it from the Ctrl o then c configuration screen). It starts in locked mode and you press Ctrl g first, then the mode letter (p pane, t tab, s scroll, ...). That's what I use day to day, it stays out of NeoVIM's way.

Configuring it (if you want to)

The defaults are good, and that's the whole reason I switched, but everything is configurable when you want to tweak something.

Where the config lives

Zellij looks for ~/.config/zellij/config.kdl. To start from the full default config with everything commented and explained:

mkdir -p ~/.config/zellij
zellij setup --dump-config > ~/.config/zellij/config.kdl

# see which config and layout dirs zellij is actually using
zellij setup --check

You can also change many settings live from inside Zellij with Ctrl o then c, and it will offer to save them to your config file.

A few options worth knowing

The config is written in KDL. These go at the top level of config.kdl:

// color theme, lots are built in (dracula, nord, gruvbox-dark, tokyo-night, catppuccin-mocha, ...)
theme "catppuccin-mocha"

// use the single line compact bar instead of the default tab + status bars
default_layout "compact"

// hide the borders around panes
pane_frames false

// start in locked mode (pairs with the unlock-first keybindings)
default_mode "locked"

// copy to the clipboard when you select text with the mouse
copy_on_select true

// lines of scrollback per pane
scroll_buffer_size 10000

// which shell new panes use
default_shell "zsh"

Custom keybindings

Keybindings live in a keybinds { } block, grouped by mode. You can add to or override just the keys you care about:

keybinds {
    normal {
        // alt+t for a new tab without entering tab mode
        bind "Alt t" { NewTab; }
    }
    pane {
        // use v / s for splits like vim
        bind "v" { NewPane "Right"; SwitchToMode "Normal"; }
        bind "s" { NewPane "Down"; SwitchToMode "Normal"; }
    }
}

Use keybinds clear-defaults=true { ... } only if you want to define every key yourself.

Layouts

Layouts are KDL files in ~/.config/zellij/layouts/. Here's a simple one for a coding project, an editor tab plus a tab for a dev server and a shell:

// ~/.config/zellij/layouts/dev.kdl
layout {
    default_tab_template {
        pane size=1 borderless=true {
            plugin location="zellij:tab-bar"
        }
        children
        pane size=2 borderless=true {
            plugin location="zellij:status-bar"
        }
    }
    tab name="code" focus=true {
        pane command="nvim"
    }
    tab name="run" {
        pane split_direction="vertical" {
            pane command="npm" {
                args "run" "dev"
            }
            pane
        }
    }
}

Then start it with zellij --layout dev. To see how the built in layouts are written, dump one with zellij setup --dump-layout default.

Plugins

Zellij plugins are compiled to WebAssembly (WASM), which means they run sandboxed and can be written in any language that compiles to WASM (Rust is the most common today). Plugins can add floating or in-line panes with their own UI, hook into Zellij's session/pane/tab events, and be bound to keys just like built-in modes.

Some top plugins worth trying

  • zjstatus — a highly customizable, Powerline-style status bar replacement; probably the single most popular Zellij plugin
  • zellij-forgot — an on-demand cheat sheet/keybinding helper overlay, handy while you're still learning the modes
  • room — a project/session switcher and launcher, similar in spirit to tmux's session pickers
  • multitask — run and monitor multiple background tasks from a single floating pane
  • harpoon — quick-jump between marked panes, inspired by the Vim/Neovim plugin of the same name
  • zellij-autolock — automatically locks Zellij's own keybindings when an app like Neovim or fzf grabs input, avoiding key conflicts

Plugins (and layouts) are typically referenced directly by URL in your Zellij config or layout file, and Zellij downloads and caches the compiled .wasm file the first time it loads — no separate plugin manager needed, which fits the same "sane defaults, minimal setup" theme that got me to switch in the first place.

More places to find me
Mental Health
follow me on Mastodon