Into the Void —
Leaving NixOS behind.
Six months into the Arch and NixOS dual-driver setup — and I've hopped again. What Void Linux actually is, why the switch happened, and what I got wrong along the way.
Mentally looping, then hopping again.
It's been quite a while since I've written about Linux distros. After a strange stretch of mentally looping myself — going back and forth, second-guessing, generally getting convoluted over roughly two months of using NixOS — I decided to hop again.
Into the Void. Or rather, Void Linux.
A genuinely unique, independent, stable rolling-release distribution. Built completely in-house, including its own package manager, XBPS, which handles finding and resolving packages in a way I've personally found smoother than Arch's pacman. The init system underneath — runit — is significantly more lightweight than systemd, with the ability to symlink in exactly the services you actually need, rather than everything being bundled into one sprawling, tightly-coupled codebase.
This one follows straight on from SQ08 — Arch vs NixOS, where I laid out those two as daily drivers. The full minimalist tool stack and how Linux RAM works differently to Windows lives in SQ07 — Full Stack Currents. Read together, they're the whole arc that lands here.
Why I'm still on glibc.
Before Void, I briefly tried Chimera Linux — a distro that pairs dinit (a different init system), musl as its C library instead of the more common glibc, and a set of userland tools inspired by OpenBSD rather than the usual GNU toolset.
It didn't stick. I found myself too congested and confused by the combination — three unfamiliar things changing at once — and it turned into what I'd call a double negative: a lot of the software I actually use assumes glibc and the GNU toolchain underneath it (gcc and friends), and swapping the C library out from under all of that at the same time as the init system was too much change in one direction. This was my own fault for not understanding these pieces well enough going in — not a knock on Chimera itself, which is a genuinely interesting project for the right use case.
Both are implementations of the C standard library — the foundational code that almost every Linux program relies on to talk to the operating system. glibc is the long-standing default across most major distros (Arch, Debian, Fedora), with the broadest compatibility — most proprietary software, including NVIDIA's graphics drivers, is built expecting it. musl is smaller, stricter about following standards exactly, and produces leaner binaries — but that strictness means some existing software (especially proprietary, glibc-linked programs) can fail outright or need patching to run properly.
Void Linux actually supports both glibc and musl as first-class options — it maintains separate repositories for each, built from scratch by the Void team. I'm running the glibc build specifically because it kept my existing software working without a fight while I got comfortable with everything else that was new.
A package manager built from scratch.
XBPS wasn't forked from pacman, apt, or anything else — it was written entirely from scratch in C by the Void team, specifically for Void. That from-scratch approach is part of why it feels tightly matched to the rest of the system rather than bolted on.
My original notes described the XBPS install command a little loosely. Worth being precise, since these are commands people will actually type:
xbps-install -S packagename— the-Sflag syncs the repository index (checks for the latest package list) before installing.- Adding
-y— as inxbps-install -Sy packagename— separately tells XBPS to assume "yes" to any confirmation prompts, so it won't stop and wait for you to typey. These are two different flags doing two different jobs, often used together. xbps-query -Rs searchterm— searches the remote repositories for a package by name.xbps-remove -R packagename— removes a package and cleans up any dependencies that nothing else needs anymore.
The lightweight init system.
Systemd, the init system most major distros default to, has grown into a sprawling collection of tightly-coupled components — commonly cited in the 1.2 to 1.4 million lines of code range across everything it now handles: service management, device handling, logging, networking, and more, all bundled together.
runit takes the opposite approach entirely. Its core — the actual process that supervises services — is famously small. The main files that do the heavy lifting total roughly a thousand lines of C, and the wider runit toolkit stays in the low thousands rather than the millions. It does one job — starting, stopping, and supervising services — and does it without pulling in everything else.
On Void, every available service (things like your network manager, Bluetooth, or firewall) has a folder sitting in /etc/sv/. To turn one on, you create a symbolic link — basically a shortcut — from that folder into /var/service/. runit watches /var/service/ and starts anything it finds there. No service, no folder in /var/service/, nothing runs. It's a genuinely simple mental model once it clicks.
My original draft said to remove a service by deleting it from /etc/sv/. That's not correct, and it matters: /etc/sv/ holds the actual service definition — the instructions for how to run it at all. Deleting from there removes the service from your system entirely, not just switches it off.
The correct way to disable a running service is to remove its symlink from /var/service/ instead — that folder just holds the "this is currently active" shortcuts. Keep /etc/sv/ intact unless you genuinely want the service gone for good.
To stop a service without fully disabling it — so it can still be managed by runit, just not currently running — use:
Here's the actual list of what a working desktop needs at the init level — not much more than this:
(or NetworkManager)
Yes — genuinely.
Void has been fast. Not "slightly snappier" fast — noticeably fast, in a way that's easy to feel within the first few days of daily use. Some of that comes down to how the system is written, and some of it comes down to simply delegating less to the init layer by default.
Idled around ~3GB with nothing open. Honestly unsure how much was genuine bloat versus my own config choices.
Sits closer to 1 – 1.2GB with nothing open. A meaningful gap you can feel day to day.
I can't say for certain how much of that gap traces back to runit specifically versus other differences in the two setups — but the general direction lines up with what's well documented about the two init systems' scope and complexity.
The actual point.
I'll be honest — I'm not entirely sure my obsession with running a mature, stable, resource-efficient Linux distro is strictly necessary. I'm still using a laptop that's nine or ten years old. It still works. But I don't want to be weighed down by unnecessary complexity sitting deep in the system that genuinely doesn't need to be that complicated for what I'm actually doing with it.
Overall, it comes down to this: being efficient, reasonably fast, and genuinely in control of what my system is doing — without it getting pulled into the orbit of resources stacking up in the background that I never asked for and don't need.