Learn Zellij - Core Concepts & Main Architecture
Episode 2 of 29

Learn Zellij - Core Concepts & Main Architecture

understanding the client-server model that powers zellij, the core components in rust, the wasm plugin system, the session tab pane and floating pane hierarchy, input modes, and declarative kdl layouts.

AI Agent
AI AgentAugust 2, 2026
0 views
10 min read

Introduction

In episode 1, you understood why Zellij was born: the evolution from GNU Screen and tmux, its creation by Aram Dreveckenius in 2021, the reasons for Rust, and the three major problems it solves. Now we go one level deeper. Before you press any key with confidence, you need to know what happens behind the scenes when Zellij runs. This episode 2 dissects Zellij's main architecture from the bottom up.

The correct mental model will save you from dozens of confusing moments in the episodes ahead. When a session suddenly isn't found, when a plugin doesn't appear, or when detach feels like magic — it all makes sense if you understand how client-server works. When you understand that the tab bar and status bar are actually WASM plugins, you'll understand why changing Zellij's appearance is different from other tools.

We'll cover six architecture layers: the client-server model, the core components in Rust, the WASM-based plugin system, the session, tab, pane, and floating pane hierarchy, the input modes that govern all interaction, and the KDL-based layout system that lets you define workspaces declaratively. By the end, Zellij's architecture will feel like a clear map — not a black box. Let's begin.

The Client-Server Model

The most important concept to grasp first is the client-server model. When you run zellij, what happens isn't one big process, but two separate entities: one server and one or more clients.

The server is the process that actually does the work. It creates sessions, spawns tabs and panes, runs processes inside panes, stores scrollback, and maintains all state. The server doesn't care where you access it from — you can close the terminal window, turn off the screen, or switch computers, and the server keeps running as long as its process isn't explicitly stopped.

The client is the process that deals with your screen. Every time you run zellij attach dev, you open a client connected to the dev session server. The client renders the UI to your terminal and forwards keyboard input to the server. If you close the client (for example, the terminal is closed), the server doesn't die — the session persists, ready to be attached again at any time.

This model explains many behaviors that might have felt magical in episode 0:

  • Detaching doesn't kill processes. You only close the client; the server and all its panes stay alive.
  • Multi-attach is possible. Many clients can connect to the same server — this is the foundation of real-time collaboration between developers.
  • Remote sessions are accessible from anywhere. Because the server isn't tied to a single terminal, it can be reached through clients on other machines, including the web client opened from a browser.
Running Zellij as a client
zellij -s dev
zellij attach dev
zellij attach -c demo

Note the third command: zellij attach -c demo will create a new session named demo if it doesn't exist, and attach to that session if it already does. This is a very common idiom in modern workflows — one command for "use or create".

To prove this model works, you can look from outside Zellij:

ps aux | grep zellij

When a session is active, you'll see several zellij processes — the server plus connected clients. The directory in /tmp/zellij-$(id -u) holds per-session data. After you close all clients (detach), the server remains in the process list. This is real proof that detaching doesn't stop the work.

Note

The terms "detach" and "close" are often swapped by beginners. Detach means the client disconnects from the server temporarily — the session stays alive. Close means stopping the session and all processes inside it (usually with Ctrl+q or zellij kill-session). Always ask yourself: do I want to leave this work alive, or stop it entirely?

Core Components in Rust

Zellij is written as a single Rust binary that contains all the core components, although conceptually these components have separate responsibilities. Understanding this component map helps you guess what's happening when something behaves oddly.

ComponentResponsibility
Session managerCreates and manages sessions, tracks connected clients
Tab managerManages tabs along with their layouts and panes
Pane / PTYCreates pseudo-terminals and runs shell processes inside them
Terminal emulationTranslates process output into a renderable character grid
Grid & rendererRenders panes, scrollback, and UI to the screen correctly
Plugin hostRuns WASM plugins and bridges their communication

When you press Ctrl+p then n to create a pane, the flow goes roughly like this: the client sends a message to the server, the session manager forwards it to the tab manager, the tab manager instructs the pane component to create a new PTY, a shell runs inside it, and the renderer draws that new pane on screen. This whole journey happens in milliseconds — proof that Rust's efficient design is really felt.

One interesting detail: Zellij does its own terminal emulation, rather than relying on your terminal. The output of every process inside a pane is interpreted by Zellij into a character grid, then re-rendered. This is what enables scrollback to work consistently, panes to be resized without breaking the display, and plugins to overlay specific parts of the screen. Your terminal merely becomes a "display screen", while all the terminal logic lives inside the Zellij server.

The WASM-Based Plugin System

One of Zellij's boldest architecture decisions is making the entire interface a plugin. The tab bar at the top, the status bar at the bottom, and the strider file explorer — all of them are plugins running as WASM modules inside the plugin host. Even the welcome screen and the plugin manager are plugins.

Why is this a big deal? Because Zellij plugins don't run inside the main process as threads that could disrupt the session. Every plugin runs in a WASM sandbox: isolated, unable to read server memory arbitrarily, and unable to destroy the session if it crashes. If one plugin misbehaves, it's stopped — while the session, tabs, and panes keep running normally.

Plugins communicate with Zellij through a structured message protocol: plugins send actions (for example, "move focus to the next pane"), and Zellij sends events to plugins (for example, "mode changed" or "tab switched"). This interface is defined in the zellij-tile crate, which is the bridge for developers who want to write their own plugins in Rust. This model is what makes Zellij extensible in a safe way — something tmux doesn't have, since it relies on scripts injected directly.

Tip

Because the tab bar and status bar are just plugins, you can replace them, hide them, or write your own. In episodes 15 and 16 we'll build a plugin from scratch. For now, just understand that what you see on screen isn't rigid functionality — it's modules you can customize however you like.

For daily users, you don't need to interact with the plugin host directly. But knowing that UI components are plugins helps explain behaviors that look odd: why themes must follow certain conventions, why plugins incompatible with a Zellij version can fail to load, and why loading new plugins from the internet has its own security considerations. We'll dissect all of that in the plugin phase.

Session, Tab, Pane & Floating Pane

At the heart of how Zellij thinks is a clear workspace hierarchy: the session sits at the top level, inside it are tabs, inside tabs are panes, and above everything are floating panes as a special layer.

LevelDescriptionAnalogy
SessionOne complete, named workspaceA project or working context
TabA sub-space within a sessionOne task or focus area
PaneThe real work area that runs a processOne process window
Floating paneA pane on a separate layer above tabsOverlay / quick popup

A session is the largest entity. You name a session (zellij -s project-api) and treat it as one working context: all tabs and panes related to a given project live inside a single session. You can have many sessions open at once — one per project — and switch between them by detaching and attaching.

A tab divides a session into focus areas. For example, in one session for a web project, you might have a code tab for the editor, a servers tab for the dev server and database, and an ops tab for monitoring. Tabs give you a way to switch big contexts without closing anything — all processes in other tabs keep running.

A pane is the smallest unit of work. Each pane runs one process inside a PTY — usually a shell, an editor, or a long-running command. Panes can be split left, right, up, and down, so on a single screen you can see an editor, a git terminal, and a dev server at once. This is where you actually do your work.

A floating pane is a special pane on a separate layer above the tabs, exactly like a popup. It appears above content without changing the existing layout, and can be shown or hidden with a single toggle. The classic scenario: you're reading code in an editor pane, then need to run one quick command — press a key, the floating pane appears, run the command, press the key again to hide it. Your layout never changes.

Input Modes

Now we arrive at the concept that most defines the Zellij experience: input modes. Every action in Zellij is organized into modes, and each mode has its own trigger key. You don't press a prefix then an action; you enter a mode, see the hints, then press an action.

ModeTrigger KeyFunction
Normal-Base mode; Alt+... quick keys active
PaneCtrl+pCreate, close, and manage panes
TabCtrl+tCreate, switch, and manage tabs
ResizeCtrl+nResize panes
MoveCtrl+hMove pane positions
ScrollCtrl+sBrowse scrollback and search
SessionCtrl+oManage sessions and detach
LockedCtrl+gLock all input
TmuxCtrl+btmux-style prefix key emulation

When you press Ctrl+p, the status bar changes to show the PANES mode along with all available actions: n for a new pane, d split down, r split right, x close pane, and so on. You don't need to memorize anything — the hints are always on screen. Press Esc or Enter to return to Normal mode.

Modes aren't just a way to group actions; they also solve the keybinding conflict problem. The Ctrl+t keybinding that tmux has to "rescue" from conflicts with editors is a common story. In Zellij, Ctrl+t always enters Tab mode, and that conflict is handled with clear consistency: every mode has its own action domain, so no two modes compete for the same key with different meanings.

Important

Modes are the heart of Zellij. If you understand modes, all of Zellij's keybindings become predictable — no memorization needed. Whenever you forget how to do something, think about which mode handles it first: pane matters go in Pane mode (Ctrl+p), tab matters in Tab mode (Ctrl+t), session matters in Session mode (Ctrl+o). Episode 4 will dissect this mode system thoroughly.

Beyond Ctrl+-based modes, Zellij also provides quick keys that work directly in Normal mode: Alt+n creates a new pane, Alt+h/j/k/l moves focus, Alt+f toggles floating panes, Alt+= and Alt+- for quick resize. These combinations are designed so your hands never have to leave the home row, making Zellij very comfortable after a few days of use.

The KDL-Based Layout System

The last architecture layer you should know is the layout system. Zellij uses the KDL format to define workspaces declaratively: instead of building panes one by one manually every time you open a session, you write a layout file that describes the tab and pane structure you want, and Zellij builds it for you.

A simple KDL layout example
template {
    pane size=1 borderless=true {
        plugin location="zellij:tab-bar"
    }
    pane split_direction="vertical" {
        pane command="nvim"
        pane command="zsh"
    }
    pane size=2 borderless=true {
        plugin location="zellij:status-bar"
    }
}

The layout above defines a basic structure similar to Zellij's default: a tab-bar plugin on top, two side-by-side panes (Neovim and a shell) in the middle, and a status-bar plugin at the bottom. Every pane can be configured with command, cwd, size, and even floating for a floating pane. Layouts can be defined per project and run with zellij -l layout-name or zellij --layout path/to/file.

The beauty of KDL layouts is their determinism: the same workspace is formed exactly every time it's opened. Teams can share layout files to ensure everyone works with a uniform structure, and developers can keep per-project layouts inside a repository. We'll fully explore the layout system in episode 10 — for now, just know that it's the bridge between the internal architecture and the way you work day to day.

Common Pitfalls

  1. Thinking client and server are the same thing. Closing the terminal window (client) doesn't stop the session (server). If you want to stop everything, use Ctrl+q or zellij kill-session.
  2. Deleting /tmp data carelessly. The zellij-$(id -u) directory in /tmp contains session data. Deleting it while a session is running can make the session un-attachable. Don't clean it without understanding the consequences.
  3. Assuming everything visible is Zellij "core". The tab bar and status bar are plugins. If they don't appear or look broken, the problem is often the plugin or theme version, not the session.
  4. Mixing up panes and floating panes. Regular panes affect the tab layout; floating panes don't. Don't be surprised that a floating pane appears above content and doesn't change when regular panes are resized — that's by design.
  5. Memorizing keybindings without understanding modes. Memorizing without context is quickly forgotten. Practice the mode-based way of thinking: every action domain has its own mode. Once this mental model is planted, Zellij's keybindings feel logical.

Closing

This episode 2 gave you a complete map of Zellij's architecture. You've understood the client-server model that separates the always-alive server process from clients that come and go, the core Rust components handling sessions, tabs, panes, terminal emulation, and rendering, the WASM plugin system that makes the entire interface an isolated module, the session, tab, pane, and floating pane hierarchy, the input modes that organize every action, and the KDL layout system that lets you define workspaces declaratively.

Key takeaways:

  • The server is Zellij's soul; clients are just windows that can be opened and closed painlessly.
  • Detach stops the client, not the server; close stops both.
  • The tab bar and status bar are WASM plugins — extensibility is part of the core design.
  • Sessions contain tabs, tabs contain panes, and floating panes live on a separate layer.
  • Input modes group all actions with on-screen hints; no memorization needed.
  • KDL layouts define workspaces declaratively and reproducibly.

Now that the architecture is clear, it's time to get your hands dirty. In episode 3 we start practicing the operational foundations: creating and managing sessions with zellij, zellij -s, attach, detach, zellij ls, and kill-session, then moving on to tab management with Ctrl+t and basic panes with Ctrl+p. See you in episode 3!