Contents

The Terminal Is the Best UI Ever Shipped

Contents

I manage a household’s worth of infrastructure and a small business’s worth of homelab services almost entirely from a terminal, and every time a vendor ships a slick new web dashboard for something I already manage from a shell, I end up back at the shell within a week. Not out of stubbornness — I have genuinely tried the dashboards — but because the terminal keeps winning on the one property that actually matters for infrastructure work: you can compose it with everything else you already know, and a GUI, however polished, is an island.

Composability is the whole argument

Advertisement

The single idea underneath Unix’s design philosophy, going back to the 1970s, is that small programs doing one thing well become genuinely more powerful when you can pipe the output of one into the input of another. grep, awk, sed, sort, uniq are each individually modest tools, none of them particularly clever on their own, and yet chained together they solve problems no single one of them was designed for.

1
docker logs myapp 2>&1 | grep ERROR | awk '{print $1, $2}' | sort | uniq -c | sort -rn | head

That one line extracts error timestamps from a log stream, counts how often each distinct timestamp pattern appears, and shows you the most frequent first — a rough error-frequency report assembled from five tools that have no idea any of the others exist, none of which was written with this specific task in mind. No GUI dashboard offers this kind of ad hoc composability, because a GUI’s features are fixed at the point someone designed the interface; a terminal’s power is not fixed at all, because you are the one composing it in real time against the actual problem in front of you, not the problem the interface’s designer anticipated.

Why this matters more for infrastructure than anywhere else

Application UIs get to make reasonable assumptions about what their users want, because the domain is narrower. Infrastructure work resists that narrowing — the specific combination of things you need to check, correlate or transform during an actual incident is different every time, which is exactly the situation composable small tools handle well and a fixed-feature dashboard handles only as well as its designer anticipated your specific problem. A dashboard is excellent at the tasks its designer thought of. A terminal is adequate at every task, including the ones nobody thought of, because the primitives compose rather than being enumerated in advance.

This is also why terminal-based tools tend to age so much better than their GUI equivalents. grep’s interface has not meaningfully changed in decades because the problem — find lines matching a pattern — has not changed, and the tool never had to accumulate a redesign to keep up with shifting UI fashion. A web dashboard gets rebuilt every few years as frameworks fall in and out of favour, and each rebuild is an opportunity to remove a feature you depended on, move something you knew how to find, or simply break compatibility with whatever scripted your interaction with it.

Scriptability is the feature GUIs structurally cannot match

Advertisement

Everything you do in a terminal is, by construction, already expressed as text — a command, arguments, output — which means everything you do in a terminal can be captured, replayed, scheduled and version-controlled with zero additional translation effort. A sequence of clicks in a GUI has no equivalent artefact; there is nothing to save, diff, or hand to a colleague except a screen recording or a written description of the clicks, both of which are lossy compared to the literal command that did the thing.

That gap is the entire reason infrastructure-as-code exists as a discipline. Ansible playbooks, shell scripts, cron jobs are all, at bottom, terminal commands captured in a file, made repeatable and reviewable in exactly the way a sequence of GUI interactions cannot be. A GUI can add an “export config” button to approximate this, but that is a feature bolted on to compensate for the interface’s fundamental non-scriptability, not a native property of the interface the way it is for a shell.

The terminal dashboards worth actually running

None of this is an argument against monitoring interfaces generally — it is an argument for terminal-native ones over web dashboards for the specific job of a quick, always-available system check. Glances gives you CPU, memory, disk, network and per-process detail in one SSH session, with no browser tab, no separate port to expose, no authentication layer beyond the SSH session you already needed anyway. For container logs specifically, a tool like Dozzle is a reasonable middle ground — a web UI for the specific job of tailing container logs without memorising fifteen container names — and I use it precisely because it does not try to replace the terminal, it removes one specific piece of terminal friction (remembering exact container names for docker logs -f) without trying to become a general-purpose infrastructure dashboard.

The pattern worth noticing there is that the tools I actually keep are the ones that respect the terminal’s role rather than trying to replace it wholesale. A web dashboard that tries to be the single pane of glass for everything ends up mediocre at everything, because it has to anticipate every use case in advance; a small tool solving one specific piece of terminal friction, and getting out of the way otherwise, earns a permanent place.

Muscle memory compounds in a way GUIs don’t reward

A GUI’s learning curve mostly plateaus early — once you know where the buttons are, you know where they are, and further practice buys you little extra speed beyond familiarity. A terminal’s learning curve keeps paying out for years, because the thing you are actually building is a growing vocabulary of composable primitives rather than familiarity with a fixed set of buttons, and every new primitive you learn combines with everything you already knew. Learning xargs well teaches you far more than xargs itself — it makes every previous tool in your vocabulary more powerful, because now anything that produces a list of things can feed anything else that acts on one thing at a time, a combination that did not exist for you before you learned that one tool.

Shell history is a smaller version of the same compounding effect. A terminal remembers every command you have run, searchable with Ctrl-R, which turns solving a problem once into solving it permanently — the next time you hit a similar situation, the exact command is a reverse-search away rather than a re-derivation from scratch. tmux or screen add persistence on top of that: a long-running session survives an SSH disconnection, a laptop closing its lid, a flaky Wi-Fi connection dropping mid-task, none of which a browser tab running a web dashboard survives with its state intact in the same way, since most web UIs assume a live connection and lose meaningful state — an in-progress form, a half-scrolled log view — the moment that connection drops.

Keyboard-only operation is the last piece of the compounding effect, and it matters more than it sounds like it should for anyone doing this for hours a week. Every context switch from keyboard to mouse and back costs a small but real amount of time and, more importantly, breaks the flow of whatever you were thinking through. A terminal session, tmux pane-switching and shell completion together mean an entire investigation — checking three services, correlating their logs, restarting one — happens without your hands leaving the keyboard once, which is a genuinely different cognitive experience from tabbing between browser windows and clicking through a dashboard’s navigation for the equivalent task.

Troubleshooting the terminal-specific gremlins

Broken box-drawing characters or garbled colours over SSH almost always trace back to a TERM environment variable mismatch between client and server — the terminal emulator advertises a terminal type (xterm-256color, say) that the remote shell’s terminfo database does not recognise, so it falls back to a much more limited rendering. echo $TERM on both ends, and installing the matching terminfo entry on the remote host (ncurses-term on Debian-based systems covers most of them) resolves nearly every case of this.

Locale-related garbling — accented characters or box-drawing glyphs rendering as question marks or boxes — is usually a mismatch between the locale your terminal emulator is configured for and the one the remote shell is running under. locale on the remote host will show you what is actually configured, and setting LANG=en_GB.UTF-8 (or your preferred UTF-8 locale) consistently on both ends, rather than assuming they match, fixes the majority of these.

Copy-paste behaving strangely inside tmux or screen — pasted text appearing with unwanted auto-indentation, or multi-line pastes executing line by line as separate commands — is a bracketed-paste-mode mismatch, where the terminal emulator supports it but the multiplexer or shell configuration in between does not pass the bracketing sequences through correctly. Enabling bracketed paste explicitly in your shell’s readline configuration, rather than living with the workaround of pasting into a scratch buffer first, is worth the five minutes it takes to fix properly once you have hit it more than a couple of times.

A terminal that appears to hang after Ctrl-S is simply Unix flow control doing exactly what it was designed to do decades before anyone using the terminal today ever hit it by accident, rather than any kind of crash — Ctrl-S pauses output, and Ctrl-Q resumes it, a piece of muscle-memory trivia that has caused more panicked SSH reconnections than any actual bug I have encountered in thirty years of terminal use combined.

A tmux session that seems to have vanished after a host reboot is not actually a tmux bug either — sessions live in the memory of the tmux server process, which dies with the reboot along with everything else, so a session surviving a genuinely rebooted host was never a property tmux promised. What it does promise is surviving your client disconnecting — a laptop sleeping, an SSH connection dropping — while the host itself stays up, and confusing the two leads to a genuine sense of loss the first time a host reboot takes a long-running session with it. tmux-resurrect and similar plugins exist specifically to persist session layout across a full server restart, which is worth setting up once you have been burned by the distinction between the two failure modes.

A terminal-first habit that pays off beyond the terminal itself

The discipline of doing infrastructure work through composable commands rather than GUI clicks has a side effect worth naming: it makes the boring reliability work — the systemd units, the healthchecks, the habits that keep a server quietly staying up for months without intervention — dramatically easier to actually implement, because that work is itself just more terminal commands captured in a config file rather than a separate skill you have to context-switch into. A GUI-first operator has to translate “I want this service to restart automatically and alert me if it doesn’t” into whatever buttons a specific dashboard happens to expose for that. A terminal-first operator writes the systemd unit directly, because writing text that describes the desired behaviour precisely is the native mode of working they are already in for everything else.

Is it still the best interface

For infrastructure work specifically — anything where the actual task varies by the day and composing existing tools ad hoc beats anticipating every workflow in advance — yes, decisively, and I don’t expect that to change while Unix’s small-tools philosophy remains the substrate everything else is built on. Graphical tools earn their place for genuinely visual tasks — a network topology diagram, a time-series graph you want to eyeball for a trend — where a wall of text is objectively the wrong representation. But for the actual work of running infrastructure, the terminal’s composability is the genuine, durable reason it keeps outlasting every dashboard built to replace it.

Advertisement
Advertisement
Smarc
Written by Smarc

Founder and editor of vo.rs. A lifelong tinkerer who self-hosts far more than is sensible, hardens Linux boxes for fun, and prods the latest AI tools to see what they can really do. The how-to guides here are the notes Smarc wishes had existed the first time round.