Let’s get this out of the way: I love tmux. Gaining the ability to multi-task within the terminal was a monumental productivity boost for me, and if you’ve used it in the past, you probably have similar stories about how it leveled up your workflow. It’s fast, it’s well-supported, and it has a plethora of features you can invoke with just a few keystrokes.
…and personally, I can only remember about a dozen of them.
Even though I used tmux frequently, the vast majority of my usage was covered by a small fraction of its feature set. I was aware that there was other functionality available, but I interacted with those pieces so infrequently that I never committed them to memory. As with so many rarely-used tools, I began to rely on the documentation or help menu whenever I needed to branch outside of my comfort zone. A chasm began to grow between the few keybindings that I knew by heart, and all of the other features that took effort to hunt down.
But I’m getting ahead of myself.
What Is a Terminal Multiplexer?
A terminal multiplexer is a program that allows you to interact with multiple terminal sessions within a single interface. That explanation is generic and rather unhelpful on its own, but it becomes more meaningful when you imagine the use cases it could support.
Maybe you need to have two shells open at once, side by side each other. Maybe you need to maintain an ssh
session on a remote machine while switching back and forth with your local session. Maybe you simply need to run multiple commands concurrently while keeping their execution environments and outputs separate. These are things that a terminal multiplexer can provide.
Mechanically, this virtualization is made possible through the multiplexer’s session management. Rather than being limited to a single shell within your terminal, a multiplexer creates virtual shells grouped within “sessions,” where each session exists as its own process within the operating system. This decouples that shell from the terminal being used to render it, granting more flexibility in what is shown to the user regardless of what is happening within that shell.
This also allows for the possibility of “detaching” from a session, effectively minimizing the session into the background where it’s disconnected from the user’s terminal window. Then, a user can leverage the multiplexer’s session manager to “reattach” to that session and resume exactly where they left off.
Because of these session management features, another common use-case for a terminal multiplexer is to kick off some long-running command within its own session, allowing it to continue running in the background even after the initial terminal window has been closed or the user has logged out. This can be very handy when executing commands on a remote server over ssh
, and it was this exact workflow that caused me to start using the tmux
command in the first place.
What Is tmux?
Put simply, tmux is a terminal multiplexer. Perhaps more accurately, it is an incredibly popular terminal multiplexer and is widely considered to be the industry standard over competing tools. Fellow Keyhole consultant Rachel Walker created a great introduction for tmux in her post, Scripting Development Environment Setup with tmux. Since the tmux user interface is the most relevant part for this post, I’ll summarize the building blocks here.
When you run the tmux
command, your terminal switches focus to the tmux interface. Your shell now lives within a pane, and panes live within windows, which exist within sessions.
- Pane: Where you can interact with your shell
- Window: Visual grouping of panes
- Session: Process-level grouping of windows
See the following terminal screenshot from the tmux Getting Started page for a visual example. This shows an active tmux session where multiple panes are arranged within a window.
The “window management” provided by these layers of abstraction allows for some very powerful customization. Users can leverage these building blocks, combined with the series of built-in commands offered by tmux, to achieve virtually whatever multi-shell workflow they desire.
So then, where does zellij come in?
Zellij
Zellij is also a terminal multiplexer. Similar to tmux, zellij also structures its “window management” philosophy into three primary layers.
Panes live within tabs (instead of windows), which live within sessions. The following image from the zellij Basic Functionality tutorial illustrates these similar concepts.
However, if you look closely at the bottom of that image, you begin to see where the philosophies of zellij and tmux begin to diverge. By default, the bottom bar of zellij is reserved for a dedicated reminder of its keybindings.
Note: The zellij status bar has since been redesigned to take up only a single line by default, as shown below:
Though concise, that status bar covers all of the keybindings that I need. This is because it updates based on the context of what you’re currently manipulating. For example, if you press Ctrl+p
to enter “pane mode,” the bar will update to show the keys that are applicable to that mode. See the following gif from that feature’s pull request for an animated example.
For me, this is groundbreaking. Where the tmux solution was to provide a reference list of keybindings, this contextual display used by zellij removes that necessity outright. Rather than remembering that Ctrl+p c
allows me to rename a pane, I simply have to look down to see that Ctrl+p
enters the “pane mode,” where c
is the rename key.
Memory Magic
Touting this as some profound improvement sounds absurd, at least until we realize that this benefit is twofold:
- (Obvious) I now have a constant visual reinforcement for the key combination I’m using to perform a task.
- (Less obvious) This visual reinforcement layer allows me to also see the other commands which apply to that context, even if they aren’t the ones that I’m using.
In my opinion, this is the real magic of using zellij. From memory, I can tell you with confidence which combination of keystrokes will let me synchronize my text input across all panes within a tab, even though (at time of writing) I have literally never used that feature before.
I can still memorize keybindings the traditional way for things that I use frequently, but I no longer have to check a reference for the remainder because that reference is built directly into the user interface by default. And if I ever get to the point where I’ve memorized all of the features that I care about and I want to reclaim that extra line of screen real estate, I can simply update my configuration to hide the status bar.
The current version of zellij also boasts some other selling points:
- A
tmux
mode, which swamps many of the keybindings for tmux defaults - A layout configuration layer that allows you to define your own custom arrangements for panes and tabs
- A command script system that allows you to automate actions (even those available through the user interface)
- Ex: Open a zellij floating pane, run a command, then copy the output to your editor in a new pane
- A web assembly plugin system, with a growing ecosystem of provided plugins
This feature set would be an ambitious goal for many open-source projects, and it’s reassuring that zellij has managed to release them after having been around for only a couple of years (the first GitHub tag was from January of 2021).
Downsides
In case you missed that “only a couple of years” comment above, I’ll state it here plainly: zellij is nowhere near as mature as something like tmux. It’s already great for me, but it still has some rough edges to be aware of.
The zellij project roadmap, while refreshingly transparent, lists several remaining features which have yet to be implemented. Native support for Windows users (those who don’t use wsl
) is still missing, managing ssh
sessions is still a little clunky, and the community still has room to grow.
It may reach a good level of maturity over time, and the level of progress thus far has been impressive to watch, but this disclaimer is still necessary for now. It is very much still a work-in-progress.
Conclusion
Even with that caveat, zellij has proven to be surprisingly effective in my usage. My everyday workflow fits nicely within its existing feature set, and I thoroughly enjoy how easily I’m able to learn and leverage new features as updates are released. Despite a long history with tmux, I am glad that I made the switch.
If you’re happy with your current multiplexer setup, great! You’re already set! However, if you’re curious about finding some improvements, then I encourage you to look through the Screencasts & Tutorials section of the documentation to see zellij in action, or to keep an eye on the GitHub repository where it’s being developed.