bringing closed workspaces back to life: automatic serialization of layout, tabs, panes, and running commands; options from session_serialization to serialize_pane_viewport; and fast restore via the CLI or session-manager.

After episode 16, where you successfully built your first Rust and WASM plugin, we now go up a level: making your workspace not only comfortable, but also hard to lose. Episode 17 covers Session Persistence & Resurrection — Zellij's ability to record a session's entire state to disk automatically, then bring it back to life whenever needed, even after a computer reboot.
Imagine the most painful scenario: you're debugging a gnarly problem with five panes open — editor, server logs, test runner, and two shell panes — when suddenly the laptop dies from a dead battery. Without persistence, all that context is gone and you have to rebuild from scratch, trying to remember which command was running in which pane. With session resurrection, Zellij saves everything automatically every second, and you just type one command to return to the point before everything collapsed.
Why does this matter? Because detaching isn't enough. Detach keeps a session alive as long as the Zellij server process is running; the moment the machine reboots, all sessions die too. Resurrection is the answer for the next layer: a dead session can be reborn from a record. In this episode we discuss the session serialization mechanism behind the scenes, the session_serialization configuration and its derivative options, how to manage and restore sessions via the CLI and session-manager, and how working directories, environments, and scrollback get saved too. By the end of the episode, you'll have a workflow that survives a reboot without losing a single pane.
Since version 0.39, Zellij has built-in session resurrection. Every running session is serialized to disk periodically — specifically, Zellij writes session data to the cache system every one second. The recorded data includes the session layout: the number of tabs, the pane arrangement, each pane's working directory, and the commands running in command-type panes. When a session ends — whether closed intentionally via Ctrl+q, dies from a crash, or the Zellij server is stopped — that data isn't discarded; it's saved as an "exited" session ready to be resurrected.
It's important to understand the difference between these two terms: attach and resurrect.
| Operation | Session Condition | What Happens |
|---|---|---|
| Attach | Still alive | Connects a client to the session; all processes inside keep running, truly uninterrupted |
| Resurrect | Already exited / dead | Recreates the session from serialized data: the layout is rebuilt, commands sit waiting for confirmation |
When you resurrect a session, Zellij rebuilds the tabs and panes, restores each working directory, then places the previously running commands behind a Press ENTER to run... banner. This design is intentional: Zellij won't blindly re-run commands, because a command like rm -rf shouldn't execute just because you pressed Enter on a resurrect prompt. You must affirm, one by one or all at once, that those commands really should be run.
The serialization result itself is stored as a KDL layout file in Zellij's cache folder — on Linux usually in ~/.cache/zellij/. Open one of those files and you'll find a familiar structure, exactly like layouts you'd write yourself:
layout {
session_name "dev"
tab name="Editor" {
pane command="nvim"
pane command="cargo watch -x run"
}
tab name="Logs" focus=true {
pane command="journalctl -f"
}
}Because the format is standard KDL, this file can be read, edited, and reloaded with zellij --layout. This opens interesting possibilities: a formerly ad hoc work session can now become an official layout you version alongside your code, or a starting point for team collaboration.
Note
One limitation you must understand: resurrection restores structure and commands, not the state of running processes. In-memory state — a REPL halfway through typing, variable values in a Python session, uncommitted output — can't be serialized. What can be restored is only the layout and the commands to be re-run from the start. This expectation matters so you aren't surprised when resurrecting a REPL session that turns out to be "back at the beginning".
The resurrection feature is active by default. In config.kdl, the option lives in the options block and is called session_serialization. You can check or modify it like this:
options {
session_serialization true
pane_viewport_serialization true
scrollback_lines_to_serialize 50000
default_cwd "~/projects"
}The first option, session_serialization true, is the master switch: it ensures the layout, tabs, panes, and running commands are serialized. The next two options deepen the fidelity of restoration:
| Option | Default | Function |
|---|---|---|
session_serialization | true | Saves the layout, tabs, panes, cwd, and running commands for resurrection |
pane_viewport_serialization | false | Saves the viewport portion visible on screen, plus scrollback, for restoration |
scrollback_lines_to_serialize | 0 (all) | Limits how many scrollback lines are serialized when the viewport is enabled |
post_command_discovery_hook | no value | Commands that modify the result of running-command discovery before serialization |
pane_viewport_serialization is the option that makes resurrection feel like a "time machine": not just the layout comes back, but each pane's screen contents and scrollback history are restored too. scrollback_lines_to_serialize is useful for limiting the load — a value of 0 means saving the entire scrollback, which of course takes up more cache space. post_command_discovery_hook is useful for cases where Zellij fails to detect a running command because it's wrapped, for example to strip a sudo prefix from discovered commands.
Important
Watch out for the trade-offs. Enabling pane_viewport_serialization true together with scrollback_lines_to_serialize 0 will save the entire scrollback every second — your cache folder can balloon quickly on active sessions. Start with a bounded value like 50000 lines, or limit it to truly critical sessions. Some options only take effect after Zellij is restarted, so after changing config.kdl, close all sessions and restart so you aren't confused by unchanged behavior.
Once resurrection is active, the zellij ls (list-sessions) command doesn't just list running sessions — it also shows exited sessions that are still stored:
zellij lsSession name Status
dev RUNNING
pipeline EXITED - attach to resurrectTo resurrect, simply attach to that session — Zellij will detect that the session is no longer alive and rebuild it from the serialized data:
zellij attach pipelineIf you're sure all recorded commands are safe to run, add --force-run-commands to skip the confirmation banners and run everything immediately:
zellij attach pipeline --force-run-commandsExited sessions that are no longer needed can be permanently deleted. Remember the difference: kill-session only applies to alive sessions, while delete-session deletes serialized sessions:
zellij delete-session pipeline
zellij delete-all-sessionsThere's one more interesting route: because resurrection data is stored as a KDL layout file, that file can be loaded like a regular layout — it can even be shared with another machine. Compare the two restore approaches:
zellij attach pipelineThe second approach is useful when you want to save a session snapshot as a permanent layout, modify it, or share it with teammates. A serialized layout is basically plain KDL that can be read and changed.
A more convenient way to do all these operations is through session-manager, a built-in plugin you can open with Ctrl+o then w. Inside, live and exited sessions are shown in a single list; press Tab to toggle showing EXITED sessions, then select one with Enter to resurrect. Permanent deletion can also be done directly from this interface, without leaving the session. The interface also does fuzzy searching on session names, so switching or restoring sessions across dozens of workspaces feels light. We'll dissect session-manager in full detail in episode 18.
Tip
A small habit that helps enormously: before closing a session whose value you want to keep, open session-manager with Ctrl+o then w, rename the session with Ctrl+r to something descriptive, then exit with Ctrl+q. The result: your zellij ls list shows exited sessions with clear names — like debug-auth-fix or migration-test — so resurrection feels like reopening a work bookmark, not guessing among random names.
Persistence isn't only about layout; Zellij also records the environment in which a session ran. There are two things to understand: the working directory and environment variables. Both can be set from the start via a layout, so when a session is resurrected, everything returns to the right place.
layout {
template {
ZELLIJ_ENV "production"
APP_LOG_LEVEL "debug"
}
tab name="editor" {
pane cwd="/srv/app" command="nvim"
}
tab name="shell" {
pane cwd="/srv/app"
}
}The template block defines environment variables injected into every pane in the session. Because these variables are set when the session is created, their metadata is stored along with the resurrection data — when the session is rebuilt, the variables are available again. Meanwhile, the cwd attribute on each pane determines the working directory; on resurrection, Zellij restores your position in the same directory.
Note
Understand that the serialized environment is session metadata, not your entire shell environment. If you manually export a variable mid-session with export FOO=bar, it lives inside the running shell process and isn't serialized. The correct pattern: define important variables through the template block in a layout or when creating a session, so they're recorded as part of the session itself.
Sometimes you need more than restoring a session — you want to keep evidence in the form of scrollback contents for documentation or incident reports. Zellij provides several paths for this.
The interactive way: enter Scroll mode with Ctrl+s, then press e to open the active pane's entire scrollback in $EDITOR. You can save that file, or even tidy it up before saving. The automated way: use the dump-screen CLI action, which outputs the viewport and scrollback contents to STDOUT so they can be redirected to a file:
zellij --session dev action dump-screen --full > /tmp/dev-output.txtThis command works both from inside and outside a session — you just name which session's contents you want. Combining dump-screen with resurrection makes an incident documentation workflow complete: scrollback is saved as an artifact, and if the context is still needed, the session can be resurrected to continue the investigation.
A more sophisticated pattern: because scrollback can also be serialized via pane_viewport_serialization, you don't need to save a dump file every time. Just make sure that option is active, let Zellij record the scrollback periodically, and take a dump-screen only when it's really needed. That way, incident documentation is always available, and in-progress work traces stay safe even when you forget to save anything manually. For a more automated flow, episode 13 shows how pipes and CLI actions can trigger a snapshot at specific moments — for example when a test fails or a build process finishes.
kill-session on an exited session. kill-session only kills alive sessions; serialized sessions are deleted with delete-session. Mixing the two up leaves you wondering why a session "won't die" — when its status is actually EXITED.Ctrl+o then d) so processes keep running.pane_viewport_serialization true without a scrollback limit. Zellij's cache folder can balloon drastically. Always set scrollback_lines_to_serialize to a sensible value, and monitor cache size if you run many sessions at once.Ctrl+q.template, and let the application pull them from a secure environment at runtime.In this episode 17, you equipped your Zellij workspace with long-term memory. We started from how session resurrection works — automatic serialization every second that records layout, tabs, panes, and running commands — then tuned restoration fidelity via session_serialization, pane_viewport_serialization, and scrollback_lines_to_serialize. You also learned to manage exited sessions via zellij ls, attach, delete-session, to take advantage of serialized layout files, to set per-session working directories and environments through a layout, and to capture scrollback for documentation.
The points to take away:
Press ENTER to run... banner for safety.session_serialization is on by default; increase fidelity with pane_viewport_serialization.delete-session deletes an exited session, kill-session for a live one.Remember, the Learn Zellij series consists of 28 episodes that build on each other. Persistence makes your sessions last, but living with many sessions at once demands tidy management. In episode 18 we discuss Session Manager & Multi-Session Workflow: using the session-manager plugin to navigate, rename, and switch sessions, one-session-per-project patterns, parallel workflows, and fzf integration for switching sessions in the blink of an eye. See you in episode 18!