Posted on:July 31, 2026 at 12:00 AM

Getting Started with Zellij: A Friendly Guide to the Terminal Workspace

Getting Started with Zellij: A Friendly Guide to the Terminal Workspace

Getting Started with Zellij: A Friendly Guide to the Terminal Workspace

What is Zellij?

Zellij is a terminal multiplexer — the same category as tmux and GNU screen. You run it once, and inside it you get panes (split views), tabs, and sessions that keep running after you close your terminal.

The pitch is right in the tagline: “a terminal workspace with batteries included.” Where tmux hands you a blank screen and a config file, Zellij shows you a status bar that lists your keybindings as you go, ships with a session manager, a file browser, and a plugin system, and does something genuinely useful out of the box on the first run.

It’s written in Rust, it’s open source (MIT), and as of 0.44 it runs natively on Linux, macOS, and Windows.

This post walks through:

  1. Installing Zellij.
  2. Your first five minutes — the parts you actually need.
  3. Panes, tabs, and the mode system.
  4. Sessions: detaching, reattaching, and surviving a reboot.
  5. Configuration (config.kdl) with a sane starter setup.
  6. Layouts — describe your project workspace once, open it forever.
  7. Driving Zellij from scripts with the CLI.
  8. Sharing a session in a browser.
  9. Notes for people coming from tmux.

1. Install

macOS

brew install zellij

Linux

Arch (pacman -S zellij), Alpine (apk add zellij), and Nix (nix-env -iA nixpkgs.zellij) all have current packages. Debian, Ubuntu, and Fedora don’t package it at the time of writing — grab the static binary instead:

curl -L https://github.com/zellij-org/zellij/releases/latest/download/zellij-x86_64-unknown-linux-musl.tar.gz \
  | tar xz
sudo mv zellij /usr/local/bin/

Any platform with Rust

cargo install --locked zellij

cargo install compiles from source and takes a few minutes. If you’d rather not wait, cargo binstall zellij downloads the prebuilt binary instead.

Windows

Since 0.44 there are native Windows binaries on the releases page. Extract and run zellij.exe from PowerShell or Windows Terminal.

Verify

zellij --version
zellij setup --check   # prints the config/layout/data dirs Zellij is using

zellij setup --check is worth running now — it tells you exactly where Zellij expects your config to live, which saves confusion later (the path differs on macOS; more on that below).

2. Your First Five Minutes

Just run it:

zellij

You’ll land in a single pane with a tab bar on top and a status bar at the bottom. That status bar is the whole onboarding story: it lists the available modes and, once you enter one, the keys inside it. You don’t have to memorize anything on day one — you read the bar.

Four things to try immediately:

WhatKeys
New paneAlt n
Move between panesAlt h / j / k / l (or arrow keys)
New tabCtrl t then n
Detach (leave it running)Ctrl o then d

After detaching, run zellij attach to come right back where you left off.

The one gotcha to know up front: Ctrl q quits — it kills the session and everything in it, no confirmation. Ctrl o then d detaches and leaves everything running. Learn the difference before you learn anything else.

3. Panes, Tabs, and Modes

The mode system

This is the one concept that makes Zellij click. Instead of tmux’s single prefix key followed by a one-shot command, Zellij has modes. You press Ctrl + a letter to enter a mode, then press plain letters to act, and Enter or Esc to go back to Normal.

ModeEnter withFor
PaneCtrl psplit, close, fullscreen, float, rename
TabCtrl tnew, close, rename, jump by number
ResizeCtrl ngrow/shrink the focused pane
MoveCtrl hrelocate a pane in the layout
ScrollCtrl sscrollback, search, edit history
SessionCtrl odetach, session manager, config, sharing
LockedCtrl gpass every key through to the app
TmuxCtrl btmux-compatible bindings

The status bar shows the keys for whichever mode you’re in, so the practical workflow is: press Ctrl + something, read the bar, press the letter.

Pane mode (Ctrl p)

n   new pane            f   toggle fullscreen
d   split down          w   toggle floating panes
r   split right         e   float ↔ embed the focused pane
s   new stacked pane    i   pin a floating pane (stays on top)
x   close pane          c   rename pane
h/j/k/l  move focus     z   toggle pane frames

Tab mode (Ctrl t)

n   new tab             1-9  jump to tab N
x   close tab           Tab  toggle last two tabs
r   rename tab          b    break pane out into its own tab
s   sync input to all panes in this tab

s (sync) is a small gem: type once, and the input goes to every pane in the tab. Handy for running the same command on four SSH sessions.

Scroll mode (Ctrl s)

j/k or ↑/↓   line up/down       s   search
Ctrl f/b     page down/up       e   edit scrollback in $EDITOR
d/u          half page          Ctrl c   jump to bottom

Ctrl s then e is the standout: it dumps the pane’s scrollback into your $EDITOR. Full search, copy, and save on a wall of build output, using the editor you already know.

Shortcuts that work in every mode

These skip the mode dance entirely:

Alt n         new pane
Alt h/j/k/l   move focus (Alt h/l also switches tabs at the edges)
Alt f         toggle floating panes
Alt +/-       resize focused pane
Alt [ / ]     cycle through swap layouts
Ctrl g        lock / unlock
Ctrl q        quit (careful)

Alt [ and Alt ] are underrated: Zellij ships with preset arrangements, and cycling them re-flows your existing panes without you having to resize anything by hand.

Floating and stacked panes

Two pane types you don’t get in tmux:

Floating panes (Alt f) hover above the layout like a window. They keep running when hidden, so they’re the natural home for a long build, a docker compose logs -f, or a quick scratch shell. Ctrl p then e converts a floating pane into a tiled one and back.

Stacked panes (Ctrl p then s) pile panes on top of each other as a list, showing one expanded at a time. When you have eight things open and no horizontal room left, this keeps them all reachable with the arrow keys instead of squeezing each into a 12-column sliver.

Mouse

Mouse support is on by default: click to focus a pane or tab, drag a border to resize, Ctrl+drag a floating pane to move it, Ctrl+scroll to resize the focused one. Zellij also detects file paths in output — click one and it opens in your editor in a floating pane, jumping to the right line number when the path has one.

4. Sessions

A session is the container for all your tabs and panes. It lives in a background server process, so closing your terminal (or losing an SSH connection) doesn’t kill it.

# Start a named session
zellij -s myproject

# List what's running
zellij ls

# Attach — to a name, or with no argument for the most recent
zellij attach myproject
zellij attach

# Attach, creating it if it doesn't exist (great for shell aliases)
zellij attach -c myproject

# Clean up
zellij kill-session myproject
zellij kill-all-sessions

Detach with Ctrl o then d. Inside a session, Ctrl o then w opens the session manager: a searchable list of every session, running or not, that you can switch to without dropping to the shell first.

Session resurrection

By default Zellij remembers a session’s structure after it exits — the tabs, panes, working directories, and the commands that were running. Attaching to a dead session recreates the whole arrangement, and each command pane comes back suspended so you can press Enter to re-run it.

To also survive a reboot, turn on serialization in your config:

session_serialization true
serialize_pane_viewport true   // also restore what was on screen
scrollback_lines_to_serialize 10000

This is not tmux-resurrect-with-plugins. It’s a config line.

To clear out old dead sessions:

zellij delete-session old-thing
zellij delete-all-sessions -y

Auto-attach on shell start

If you want every terminal window to land in the same session, add this to your ~/.zshrc:

eval "$(zellij setup --generate-auto-start zsh)"

Use bash or fish for those shells. It respects ZELLIJ_AUTO_ATTACH and ZELLIJ_AUTO_EXIT if you want to tune the behavior.

5. Configuration

Zellij configures itself in KDL, a config language that reads like a cleaner JSON with braces and no commas.

Where the file lives

zellij setup --check
  • Linux: ~/.config/zellij/config.kdl
  • macOS: ~/Library/Application Support/org.Zellij-Contributors.Zellij/config.kdl

If you sync dotfiles across machines, the macOS path is annoying. Export ZELLIJ_CONFIG_DIR=~/.config/zellij in your shell profile and both platforms use the same location.

Dump the defaults, fully commented, as a starting point:

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

You don’t have to restart to see changes — Zellij watches the config file and applies most settings live. You can also edit settings from inside a session with Ctrl o then c, which opens a UI that writes the file for you.

A reasonable starter config

// ~/.config/zellij/config.kdl

theme "catppuccin-mocha"

// "compact" hides the tab bar and shrinks the status bar to one line —
// more room for your actual work once you know the keys.
default_layout "compact"

// Copy to the system clipboard (macOS; use wl-copy or xclip on Linux)
copy_command "pbcopy"

// Selecting text with the mouse copies it immediately
copy_on_select true

// Survive reboots
session_serialization true
serialize_pane_viewport true
scrollback_lines_to_serialize 10000

scroll_buffer_size 50000

// What to do about a Zellij session running inside a pane (e.g. over SSH).
// "ask" prompts; "descend" always hands keys to the inner session on focus.
nested_session_handling "ask"

keybinds {
    // Alt+n collides with some terminal emulators; add a second binding
    normal {
        bind "Alt Enter" { NewPane; }
    }
}

Themes ship built in — zellij setup --dump-config lists them, and the config UI (Ctrl o then c) lets you preview them live.

Turning off pane frames

The borders around each pane cost you two rows and two columns per pane. Ctrl p then z toggles them; pane_frames false in the config makes it permanent. With copy_on_select on and frames off, Zellij gets out of the way considerably.

6. Layouts: Your Project Workspace, Automated

This is the feature that pays for itself. A layout is a KDL file describing tabs, panes, working directories, and commands — so zellij --layout dev reconstructs your entire working setup in one keystroke.

A minimal one:

layout {
    pane
    pane split_direction="vertical" {
        pane
        pane command="htop"
    }
}

A real one for a web project:

layout {
    cwd "."

    // Without this, your tabs come up with no tab/status bars.
    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 split_direction="vertical" {
        pane size="65%" name="editor" {
            command "nvim"
            args "."
        }
        pane split_direction="horizontal" {
            pane name="shell"
            pane name="git" {
                command "git"
                args "status"
                close_on_exit false
            }
        }
    }

    tab name="servers" {
        pane name="dev server" {
            command "npm"
            args "run" "dev"
            // Comes up paused — press Enter to actually start it
            start_suspended true
        }
        pane name="tests" {
            command "npm"
            args "test" "--" "--watch"
            start_suspended true
        }
    }

    tab name="files" {
        pane {
            plugin location="zellij:strider"
        }
    }
}

↓ Download zellij-dev-layout.kdl

Drop it in ~/.config/zellij/layouts/dev.kdl and run:

zellij --layout dev

Anything in the layouts directory can be referenced by bare name. You can also point at a path (zellij --layout ./team-layout.kdl) or even a URL — Zellij will ask for confirmation before running any commands from a remote layout.

Three properties worth knowing:

  • start_suspended true — the pane is created with the command staged but not running. Press Enter to launch it. Perfect for a dev server you don’t always want up.
  • close_on_exit false — the pane survives the command exiting, showing the exit code, and Enter re-runs it. Command panes are first-class in Zellij, not just shells that happen to have something typed in them.
  • default_tab_template — a custom layout replaces the default one entirely, bars included. If your tabs come up bare, this is why.

Running zellij --layout dev while already inside a session adds those tabs to the current session instead of starting a new one. To force a new session, use zellij --new-session-with-layout dev.

Layouts are the answer to “how do I onboard someone onto this repo” — commit the layout file, and a new teammate gets your exact workspace.

Swap layouts

Alt [ and Alt ] cycle through swap layouts: preset arrangements that Zellij re-flows your current panes into. You can define your own next to a layout file (dev.swap.kdl), but the built-in ones cover most cases — the point is that resizing panes by hand is usually avoidable.

7. Driving Zellij from the CLI

Nearly everything the UI does is available as a command, which makes Zellij scriptable in a way tmux only sort of is.

# Run a command in a new pane
zellij run -- cargo test

# ...in a floating pane
zellij run --floating -- docker compose logs -f

# ...in a specific direction, with a name
zellij run --direction down --name "server" -- npm run dev

# Open a file in $EDITOR in a new pane, at a line number
zellij edit src/main.rs --line-number 42

# Fire actions at the current session
zellij action new-tab --name "deploy"
zellij action go-to-tab 2
zellij action write-chars "echo hello"
zellij action dump-screen /tmp/pane.txt

# Target a session by name from outside it
zellij --session myproject action new-pane

Set up completions and you get three short aliases for the most common cases:

# zsh — add to ~/.zshrc
eval "$(zellij setup --generate-completion zsh)"
zr cargo watch -x test      # run in a new pane
zrf htop                    # run in a floating pane
ze src/main.rs              # edit in a new pane

Since 0.44 the automation story got noticeably better for scripts: commands return the pane ID they created, --blocking and --block-until-exit-success let a script wait for a pane’s command to finish, and zellij action list-panes / zellij subscribe let you query state or stream a pane’s output to stdout as JSON. That’s enough to build a real pipeline — spawn panes, wait on them, react to the results — from a shell script.

8. Sharing a Session in the Browser

Zellij ships with a built-in web server. It’s off by default; when you turn it on, any session can be opened in a browser at a persistent, bookmarkable URL.

# Start the web server (defaults to 127.0.0.1:8082)
zellij web --start

# Check on it / stop it
zellij web --status
zellij web --stop

# Create a login token
zellij web --create-token --token-name laptop

# A read-only token for someone who should watch but not type
zellij web --create-read-only-token

Or configure it to always run:

web_server true
web_sharing "on"
web_server_ip "127.0.0.1"
web_server_port 8082

Two things worth being deliberate about:

  • Binding beyond localhost requires TLS. Set web_server_cert and web_server_key if you’re exposing this on a network. Don’t put an unauthenticated terminal on 0.0.0.0.

  • Read-only sharing is the safe default for pairing. zellij watch <session> attaches read-only from a terminal, and Ctrl o then s opens the sharing plugin to generate browser tokens.

    0.44 also added attaching to a remote session straight from your terminal, no SSH tunnel:

zellij attach https://example.com/my-cool-session

9. Coming from tmux

If your fingers already know tmux, press Ctrl b — that enters tmux mode, where ", %, c, ,, n, p, d, z, x, and the arrow keys do what you expect. It’s a bridge, not a full emulation, but it makes the first week painless.

The real differences:

tmuxZellij
Discoveryread the man pageread the status bar
Config.tmux.conf, restart to applyconfig.kdl, hot-reloaded
Workspace setuptmuxinator / a shell scriptbuilt-in layouts
Session restoretmux-resurrect pluginone config line
Floating panespopups (limited)first-class, persistent
Pluginsshell scriptsWebAssembly, any language
Browser accessbuilt in

And the honest downsides: Zellij uses more memory than tmux, it isn’t installed on every server you’ll ever SSH into, and if you have a decade of muscle memory and a tuned .tmux.conf, the switch may not buy you much. Zellij’s own docs are relaxed about this — it’s a different set of tradeoffs, not a strict upgrade.

10. Gotchas

  • Ctrl q kills the session. No confirmation. Rebind it if that makes you nervous: bind "Ctrl q" { SwitchToMode "Normal"; } under shared_except "locked".
  • Alt keys may not reach Zellij. Some terminals send Esc-prefixed sequences instead. On macOS Terminal / iTerm2, enable “Use Option as Meta key.” Otherwise add your own bindings.
  • Ctrl g locks everything. If Zellij suddenly stops responding to shortcuts, you’re in locked mode — the status bar says so. Ctrl g again unlocks.
  • Vim/Emacs users: Ctrl p, Ctrl n, Ctrl b, Ctrl s, Ctrl o, Ctrl t, and Ctrl h are all taken by Zellij. Either rebind them in config.kdl or use locked mode (Ctrl g) while you’re in the editor.
  • The macOS config path is not ~/.config. Set ZELLIJ_CONFIG_DIR if you want it to be.
  • A custom layout replaces the default one. No default_tab_template, no bars.

Next Steps

  • Plugins: the status bar, tab bar, session manager, and file browser are all plugins — anything compiling to WebAssembly can be one. Ctrl o then p opens the plugin manager. Worth a look: zjstatus (a highly configurable status bar) and zellij-forgot (a searchable keybinding cheatsheet).
  • Themes: dozens ship built in; Ctrl o then c previews them live.
  • Multiple pane select: Alt+left-click marks panes, then close, stack, or break them out to a tab in bulk.
  • Commit a layout to your repo. It’s the single highest-leverage thing here.

References

Related Posts