Last updated: March 21, 2026

Zellij is a terminal multiplexer written in Rust, designed as a more approachable alternative to tmux. It has a built-in UI with visible keybinding hints at the bottom of the screen, sensible defaults that work without a config file, and a plugin system based on WebAssembly.

For remote developers, Zellij offers session persistence like tmux, but with less configuration overhead and a layout system that uses KDL files (a readable config format) instead of shell scripts.

Install Zellij

# macOS
brew install zellij

# Linux — download binary
bash <(curl -L zellij.dev/launch)

# Or via cargo (Rust)
cargo install zellij

# Via apt (Ubuntu PPA)
sudo apt-add-repository ppa:zellij/zellij
sudo apt-get update
sudo apt-get install zellij

# Verify
zellij --version
# zellij 0.40.x or similar

Start a Session

# Start Zellij (creates a default session)
zellij

# Start with a named session
zellij --session work

# List sessions
zellij list-sessions
# or
zellij ls

# Attach to an existing session
zellij attach work
# or
zellij a work

# Kill a session
zellij kill-session work
# or
zellij k work

# Kill all sessions
zellij kill-all-sessions

Default keybindings use Ctrl-g to enter “lock mode” (pass-through for nested terminals). The mode indicator at the bottom shows your current mode: Normal, Pane, Tab, Resize, Scroll, etc.

Zellij Config File

Create ~/.config/zellij/config.kdl:

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

// Use vi-style navigation
default_mode "normal"

// Reduce theme overhead on remote sessions
theme "default"

// Pane frame settings
pane_frames false  // hide pane borders (cleaner look)

// Session persistence: sessions survive disconnects
session_serialization true

// Scroll buffer
scroll_buffer_size 50000

// Mouse support
mouse_mode true

// Key bindings — customize to avoid conflicts with nested apps
keybinds clear-defaults=true {
    normal {
        bind "Ctrl a" { SwitchToMode "Tmux"; }  // familiar prefix for tmux users
    }
    tmux {
        bind "[" { SwitchToMode "Scroll"; }
        bind "d" { Detach; }
        bind "|" { NewPane "Right"; SwitchToMode "Normal"; }
        bind "-" { NewPane "Down"; SwitchToMode "Normal"; }
        bind "c" { NewTab; SwitchToMode "Normal"; }
        bind "n" { GoToNextTab; SwitchToMode "Normal"; }
        bind "p" { GoToPreviousTab; SwitchToMode "Normal"; }
        bind "h" { MoveFocus "Left"; SwitchToMode "Normal"; }
        bind "j" { MoveFocus "Down"; SwitchToMode "Normal"; }
        bind "k" { MoveFocus "Up"; SwitchToMode "Normal"; }
        bind "l" { MoveFocus "Right"; SwitchToMode "Normal"; }
        bind "," { SwitchToMode "RenameTab"; TabNameInput 0; }
        bind "r" { SwitchToMode "Resize"; }
        bind "z" { ToggleFocusFullscreen; SwitchToMode "Normal"; }
        bind "Ctrl a" { Write 1; SwitchToMode "Normal"; }  // send literal Ctrl-a
    }
    scroll {
        bind "q" { SwitchToMode "Normal"; }
        bind "Ctrl c" { SwitchToMode "Normal"; }
        bind "j" { ScrollDown; }
        bind "k" { ScrollUp; }
        bind "Ctrl d" { HalfPageScrollDown; }
        bind "Ctrl u" { HalfPageScrollUp; }
        bind "/" { SwitchToMode "EnterSearch"; SearchInput 0; }
        bind "n" { Search "down"; }
        bind "N" { Search "up"; }
    }
    resize {
        bind "h" { Resize "Increase Left"; }
        bind "j" { Resize "Increase Down"; }
        bind "k" { Resize "Increase Up"; }
        bind "l" { Resize "Increase Right"; }
        bind "Esc" { SwitchToMode "Normal"; }
    }
}

Layouts

Zellij layouts define how panes and tabs are arranged at startup. Create them in ~/.config/zellij/layouts/:

// ~/.config/zellij/layouts/dev.kdl
// A 3-pane dev layout: editor, terminal, and log viewer

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="editor" focus=true {
        pane split_direction="vertical" {
            pane size="65%" focus=true
            pane split_direction="horizontal" {
                pane
                pane size="30%"
            }
        }
    }

    tab name="server" {
        pane split_direction="horizontal" {
            pane command="npm" {
                args "run" "dev"
            }
            pane command="tail" {
                args "-f" "logs/app.log"
            }
        }
    }

    tab name="git" {
    }
}

Start Zellij with a layout:

# Use a specific layout
zellij --layout dev

# Or by file path
zellij --layout ~/.config/zellij/layouts/dev.kdl

# Set a default layout in config.kdl
// default_layout "dev"  // add to config.kdl

Auto-Start Layout for Project

Use a shell function that starts or attaches to a Zellij session with the right layout for a project:

# Add to ~/.bashrc or ~/.zshrc

# Start or attach to a project session
dev() {
  local project=${1:-$(basename "$PWD")}
  local path=${2:-$PWD}

  # Check if session exists
  if zellij list-sessions 2>/dev/null | grep -q "^$project"; then
    echo "Attaching to existing session: $project"
    zellij attach "$project"
  else
    echo "Starting new session: $project"
    cd "$path" && zellij --session "$project" --layout dev
  fi
}

# Quick alias to attach to last session
alias zj='zellij attach $(zellij list-sessions | head -1 | cut -d" " -f1)'

SSH Persistence with Zellij

Sessions persist on the server across SSH disconnects, just like tmux:

# SSH and attach/create session (same pattern as tmux)
ssh user@server.example.com

# On server: attach or create
zellij attach work 2>/dev/null || zellij --session work

# One-liner SSH + attach from local machine
ssh -t user@server.example.com "zellij attach work 2>/dev/null || zellij --session work"

# ~/.ssh/config: auto-attach on SSH
# Host devserver
#     HostName server.example.com
#     User ubuntu
#     RemoteCommand zellij attach work 2>/dev/null || zellij --session work
#     RequestTTY force

Plugins

Zellij plugins extend functionality via WebAssembly. Install community plugins:

# Install zjstatus (a better status bar)
# Plugins live in ~/.config/zellij/plugins/

mkdir -p ~/.config/zellij/plugins
curl -L https://github.com/dj95/zjstatus/releases/latest/download/zjstatus.wasm \
  -o ~/.config/zellij/plugins/zjstatus.wasm

Reference in layout:

// In a layout file
pane size=1 borderless=true {
    plugin location="file:~/.config/zellij/plugins/zjstatus.wasm" {
        format_left  "#[fg=#9a8a8a,bold]  {session}"
        format_right "{datetime}"
        format_space ""
        datetime_format "%Y-%m-%d %H:%M"
        datetime_timezone "America/New_York"
    }
}

Zellij vs tmux Decision

Use Zellij if:

Use tmux if:

Both handle SSH session persistence equally well. The day-to-day experience with either is comparable once you learn the keybindings.

Frequently Asked Questions

Who is this article written for?

This article is written for developers, technical professionals, and power users who want practical guidance. Whether you are evaluating options or implementing a solution, the information here focuses on real-world applicability rather than theoretical overviews.

How current is the information in this article?

We update articles regularly to reflect the latest changes. However, tools and platforms evolve quickly. Always verify specific feature availability and pricing directly on the official website before making purchasing decisions.

Are there free alternatives available?

Free alternatives exist for most tool categories, though they typically come with limitations on features, usage volume, or support. Open-source options can fill some gaps if you are willing to handle setup and maintenance yourself. Evaluate whether the time savings from a paid tool justify the cost for your situation.

How do I get my team to adopt a new tool?

Start with a small pilot group of willing early adopters. Let them use it for 2-3 weeks, then gather their honest feedback. Address concerns before rolling out to the full team. Forced adoption without buy-in almost always fails.

What is the learning curve like?

Most tools discussed here can be used productively within a few hours. Mastering advanced features takes 1-2 weeks of regular use. Focus on the 20% of features that cover 80% of your needs first, then explore advanced capabilities as specific needs arise.