Learn Zellij - Performance Optimization
Series/Learn Zellij/Episode 24
Episode 24 of 29

Learn Zellij - Performance Optimization

tuning scroll_buffer_size and scrollback_lines_to_serialize to save memory, lightening the renderer load with a simple theme, keeping many sessions and plugins responsive on limited machines.

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

Introduction

Episode 23 taught you to rescue a broken Zellij. Episode 24 teaches something subtler: how to keep Zellij from breaking in the first place — by managing resources consciously. The Learn Zellij series closes the troubleshooting chapter and performance optimization with Performance Optimization in episode 24, before moving on to the modern ecosystem in episode 25.

Zellij is frugal by design: a lean Rust server process and lightweight WASM plugins. But like all terminal workspaces, the cost grows with use. Every pane is a living PTY process, every plugin renders its UI periodically, every scrollback stores thousands of lines in memory, and every serialized session writes data to disk. On modern machines this goes unnoticed; on a small VPS, an old laptop, or a container with tight limits, the difference is very real.

Episode 24 structures the tuning from the most impactful: scroll_buffer_size to control scrollback memory, scrollback_lines_to_serialize to lighten the restore process, simple themes to reduce renderer load, strategies for keeping many sessions and plugins responsive, and comprehensive resource management on limited machines. The goal isn't extreme performance, but a workspace that stays stable and comfortable in every condition.

Before diving into the details, it's important to set realistic expectations. Performance tuning in Zellij is never about one magic number — it's always about trade-offs. Reducing the scrollback buffer saves memory but trims the history you can search. Turning off serialization speeds up session exit but removes automatic restore. Simplifying the theme lightens the renderer but reduces visual comfort. Every decision in this episode is a conscious choice between comfort and resources. You decide the balance point, not Zellij.

scroll_buffer_size: Control Scrollback Memory

Every Zellij pane stores its output history in memory so you can scroll and search without limits — up to a point. The scroll_buffer_size option determines how many lines are stored per pane. Its default value is 10000 lines. While the process runs, this number multiplied by the number of active panes determines the memory load.

ValueCharacterMemory per Pane
10000Default, long historyHigh
5000Balanced between history and frugalityMedium
2000Frugal, enough for short sessionsLow

To calculate the real impact, multiply this value by the number of panes. Ten panes at 10000 lines store a potential 100000 lines of text in memory. If you rarely scroll far back, a large buffer is just wasted memory. Also remember that long lines — for example unformatted JSON output — consume more memory per line than short ones, so the real need depends heavily on the type of output you produce.

config.kdl — limit the scrollback buffer
options {
    scroll_buffer_size 3000
}

Note

scroll_buffer_size is a runtime limit: it controls memory during the session's lifetime and also limits how far you can scroll or search in the scrollback. If you routinely search old logs, don't lower it too aggressively — prioritize a value that's still comfortable for your workflow, not the smallest value.

The good news is that this setting doesn't affect already-running pane buffers until the session is restarted. After changing the value, open a new session to apply it. Also keep in mind that a small buffer narrows the search space: Scroll mode and Search work within the buffer's limits, so if you often search for patterns in old output — say, an error that appeared hours ago — a buffer that's too small makes that search impossible. Consider your search habits before lowering this number.

scrollback_lines_to_serialize: A Lighter Restore

There's a second option that's often confused with the first: scrollback_lines_to_serialize. Both talk about scrollback, but at different points. scroll_buffer_size manages runtime memory; scrollback_lines_to_serialize manages how many scrollback lines are saved when a session is serialized for restore.

When you exit a session with serialization active, Zellij saves the layout and part of the pane contents so it can be rebuilt later. The more lines serialized, the larger the file written to disk and the slower the save and restore process. If you don't need the full history after a restart — just the layout and running commands — a small value is enough.

config.kdl — reduce the serialized lines
options {
    scrollback_lines_to_serialize 500
}

Important

Don't mix them up: scroll_buffer_size limits memory while the session runs, whereas scrollback_lines_to_serialize limits the data written and restored when a session is saved. Lowering one doesn't automatically lower the other. Treat them as two separate dials controlling two different phases.

For workflows that rely on session persistence on small machines, a sensible pairing is a runtime buffer sufficient for daily work and a small serialization value so restore is fast. This combination gives full scrolling comfort while working, without excessive disk load and wait time on return. As a reference, an overly large serialization value can noticeably slow session opening, especially on machines with mechanical disks or slow storage media.

Simple Themes and Renderer Load

Zellij renders its interface through UI plugins — the tab-bar, status-bar, and other plugins — which run periodically. The renderer load is determined by two things: how often plugins refresh themselves, and how complex the display that must be drawn is. A theme with many color layers, special effects, and continuously animating plugins is heavier than a simple display.

On limited machines, reducing renderer load often shows up as a more responsive cursor and smoother scrolling. The way to do it: use a simple built-in theme instead of a heavy custom one, and disable plugins you don't actually use — every loaded plugin means extra render work.

config.kdl — simple theme and compact UI
options {
    theme "nord"
    simplified_ui true
}

simplified_ui reduces the UI elements displayed, so the renderer has less work per frame. The nord theme is chosen because its palette is simple and doesn't require much gradient computation. On very limited machines, even using the unmodified default theme already helps.

Remember the trade-off: the visual features you enjoy — animated icons, automatic theme switching, informative widgets — all have a render price. On a strong machine this price is imperceptible; on a weak machine, you have to choose which features are worth it. One of the most useful metrics is the number of running plugins: every UI plugin adds repetitive render work. A status-bar showing many widgets refreshes itself every few seconds; if you never read most of those widgets, that plugin is pure overhead.

Many Sessions and Plugins: Staying Responsive

Zellij's performance is most noticeable as the number of sessions and panes piles up. Every pane is a running shell process, and every session adds load to the Zellij server. Two dozen sessions each with a dozen panes will feel different from one tidy session with three tabs — not because Zellij is slow, but because of the real number of processes that must be maintained.

The most impactful habit is discipline: close panes that are finished, kill sessions that aren't used, and don't open a new session without a purpose. Before piling on more, look at what's already running.

Audit running sessions and layouts
zellij list-sessions
zellij action dump-layout

zellij list-sessions shows all active sessions — it's surprising how many are left over from last week. zellij action dump-layout shows session contents so you can decide which ones are worth keeping. Kill unused ones with zellij kill-session.

Beyond the number of sessions, also pay attention to session contents: the number of tabs and panes per session is the second factor determining responsiveness. Two panes exchanging large output — for example one pane running a dev server and another following its logs — keep processing data as long as both are alive. There's nothing wrong with this pattern; what matters is realizing that every "monitoring" pane is a continuous CPU cost.

Note

Rule of thumb: one session per project. When working on several projects at once, make sure each session is genuinely needed. An idle session keeps running all the processes and panes inside it — a cost that keeps running without producing anything.

The mouse also contributes to event consumption: with mouse_mode on, Zellij processes every pointer movement. If you work keyboard-first, turning off the mouse reduces event-handling work without sacrificing anything. The same applies to serialization: disabling session_serialization removes the disk-write work when exiting a session, suitable for machines with slow disks.

Also distinguish between detach and kill. Detach only disconnects the client — the session, panes, and processes inside keep running and consuming resources. Kill stops everything. If you're done with a project and won't return soon, detach isn't the answer; zellij kill-session is. This small habit alone is what most often keeps many sessions lean.

Resource Management on Limited Machines

You use all the knobs above together on machines with limited resources — a 512 MB VPS, an old laptop, or a container with tight limits. The key isn't turning off all features, but choosing the most frugal combination without losing the core workflow.

options {
    scroll_buffer_size 6000
    scrollback_lines_to_serialize 1000
}
KnobEffectFrugal Direction
scroll_buffer_sizeRuntime scrollback memoryLower it
scrollback_lines_to_serializeSerialization file size and restore speedLower it
theme and simplified_uiUI renderer loadSimplify
mouse_modePointer event processingTurn off if keyboard-first
session_serializationDisk writes when exiting a sessionTurn off if restore isn't needed

Besides configuration, apply operational habits: limit the number of tabs and panes per session, avoid unnecessary floating panes, and run only essential plugins. On a limited machine, one lean session is far more comfortable than three sessions each carrying dead weight.

Warning

Don't lower everything at once without measuring. Good performance is the result of conscious trade-offs: too small a buffer removes the history you need, disabled serialization removes automatic restore, and too plain a theme reduces visual comfort. Change one variable, feel its impact, then move on to the next.

Measure first with the tools available — htop for memory and CPU, the perceived time when opening a session — then decide which knob is most worth turning. Every machine has a different optimal point. On very constrained machines, start from the frugal profile in the code-group above, then loosen one by one only where it really feels lacking: if scrollback feels short, raise scroll_buffer_size; if restore feels slow, lower scrollback_lines_to_serialize. Conscious tuning is far better than following numbers from someone else's article.

Common Pitfalls

  1. Lowering scroll_buffer_size too aggressively. The scrollback history you need is gone. Fix: lower it gradually and test scrolling and search workflows after every change.
  2. Conflating scrollback_lines_to_serialize with the runtime buffer. Two different dials for two different phases. Fix: understand that one controls live memory, the other controls restore data.
  3. Disabling all plugins until the UI is useless. Excessive frugality sacrifices the core functions of the tab-bar and status-bar. Fix: remove plugins you don't use, keep the essential ones.
  4. Measuring performance without a baseline. You don't know whether a change really helps. Fix: record the initial condition with htop and session-open time before tuning.
  5. Leaving dozens of sessions idle. Load keeps running without producing anything. Fix: audit with zellij list-sessions regularly and kill what's unused.

Closing

Episode 24 closes the performance optimization chapter with clear tools: scroll_buffer_size to control runtime scrollback memory, scrollback_lines_to_serialize to lighten the serialization and restore process, simple themes and simplified_ui to reduce renderer load, discipline in keeping many sessions and plugins responsive, and a tuning combination for limited machines.

The points to take away:

  • scroll_buffer_size controls live memory; scrollback_lines_to_serialize controls restore data — two different things.
  • Renderer load drops with simple themes and fewer plugins.
  • One session per project, and audit with zellij list-sessions regularly.
  • Change one variable at a time, measure its impact, then continue.
  • Limited machines need conscious trade-offs, not all features at once.

Performance isn't about the highest numbers, but about a workspace that stays comfortable when resources run low. With this, Phase 6 is nearly complete — episode 24 is followed by episode 25, which begins Phase 7: Latest Stable Features (0.40 - 0.44) — tracing Zellij's modern revolution from the welcome screen and filepicker of 0.40, the plugin manager of 0.41, pinned floating panes and the theme spec of 0.42, the web client of 0.43, to remote sessions, Windows support, and CLI automation of 0.44. See you in episode 25, and may your Zellij stay light.

Learn Zellij - Performance Optimization | Learn Zellij