Skip to content

NixOS is the endgame of distrohopping

· 15 min

img

When you first start into the rabbit hole that is Linux, you see that there are hundreds if not thousands of distributions that you can pick to use.

While this can be quite intimidating, there are only a select few that are the root of the tree that all others are derived from: Debian, Arch and (some would say) Fedora/RedHat. But, there is one distribution that has lately come on the radar of the community that I would say is truly the endgame of distrohopping: NixOS.

Let’s begin.

How I got here#

Record scratch - freeze frame - Yep, that’s me. You’re probably wondering how I got here.

How did I get so far down the rabbit hole that Nix seemed like the final solution to me?

Well, I started out how every linux user does: I installed Arch Linux back in 2017, falling for the meme immediately. I remember the install taking a full weekend - everyone forgets to enable network-manager and bricks their first installation, and I was just running commands with no sense as to what they do: “what’s an fdisk?”.

Using Arch was not so bad - at least until a week later when I got a black screen after an update and didn’t know what I had done wrong, so therefore, I fresh installed again. This time with a little more inquisitiveness and understanding.

I figured it was too much work at the time to go through all the install steps, and settled into Manjaro Linux (with its graphical Calamares installer) for about a year or so, getting comfortable with the Linux way of doing things, the sudo pacman'ing everything, and overall enjoying the experience. I then wandered back to vanilla Arch Linux which I ran without issue (after understanding a bit more about how this whole management of packages and updating thing went) for another year or so.

In 2020, I had a breaking change (and a lot of time on my hands) which then pushed me to hop to Artix and then EndeavourOS and sat comfortably with that until ~2024 when being a father meant I had less time for tinkering and just wanted to get my work done.

I installed Fedora last March, and have used that for well over a year. It’s been great! I think Fedora is a solid middle ground between the bleeding edge of Arch and something more stable such as Debian. There are some older packages, and you do have to RPM install and use Flatpak quite a bit, but overall it is stable and backed by RedHat which means you are a testing ground for enterprise Linux. You also have the opportunity to use Fedora Silverblue which gets you thinking about immutability.

edit: The whole “Redhat thing” (killing off CentOS, etc.) never really bugged me, but for some, it does - to the point of saying Fedora is out of the question

However, around a month ago, I installed NixOS and now run it on all my machines with the exception of a few Debian servers that will be migrated in the future. What gives?

So, why NixOS then?#

If I like Fedora so much, why wander over to the functional, declarative, and frustrating world of Nix and NixOS?

I had been using the Nix package manager on Fedora for some time in that I could create environments for development and write scripts without polluting my main machine - and that was very nice. It gave me a glimpse into the paradigm shift, and I got addicted.

I realized that I want immutability, reproducibility, and to not ever worry about breaking a machine: I manage numerous servers (more every other day it seems), and to do so without the ability to re-create environments and quickly deploy projects is out of the question. Yes, I had a library of scripts to handle this, yes I used Docker (Podman) for containerization - and still do in Nix environments to some extent - but all of this seems archaic and messy when Nix exists.

And, after a month, I would not go back.

I will go over my reasoning for why Nix? in this post, and get your mind turning as to some of the problems we can solve by going the declarative route. Maybe you too will see why there is a lot to like about Nix and the ecosystem, about why there is an argument that declarative package management is the direction Linux should go with all package managers. I would now also make that argument after seeing what that looks like.

Before we begin: Do I recommend skipping everything and going with NixOS?

Not a chance in hell.

You do not get the deep understanding of linux systems when you use NixOS - it abstracts much of system management away. I have done my time, and now I just want something that works. If you are a new Linux user, you would be doing a disservice to yourself to not start with something a little “closer to the metal” like Arch or Debian. Did I just recommend first time users use arch over NixOS? It appears I have.

Here’s the thing though: you can install Nix the package manager on any unix based operating system (Mac too) and have many of the benefits of running NixOS - I highly recommend this. You can install home-manager as well, and manage all your user settings in a declarative, version controlled way. Just the other day my wife needed Chrome for something on her Mac, so I set up an ethereal nix-shell running chrome. When she was done, she killed the shell and Chrome went away. That’s pretty nice. Here come the Chrome fanboys…

But you don’t need all of NixOS for this, whet your appetite with Nix as a package manager, and start to see the power. Manage your config with home manager (I do some of this, but mostly symlink my configs - another post about this in the future), and see how Nix can infect your system.

Then, and only then make the jump.

What problems does Nix solve for me?#

Chaos to order#

As someone that militantly pushes to simplify all aspects of my life, NixOS scratches the itch. I effectively have one literate file that defines all of my computing infrastructure and this cannot be understated: Any machine I will touch in the future, be it server, desktop/laptop, or even phone - can be re-created with one git repo.

This may require the upfront investment to get working, but truthfully - the rest of my natural computing life is now version controlled. I no longer have to remember installation procedures (or write scripts for them), that “one little trick” to get a service properly running, nor do I have to do that across multiple machines. One file, one place, for everything.

This also means:

Safe rollbacks#

If I do create a breaking change, NixOS has previous working generations I can rollback to in the boot menu. This is huge: classically I had my fingers crossed every time I did an update, hoping that my machine would boot. One bad kernel updates, one driver breaking, and that can mean hours of trying to fix it - or a fresh installation I cannot afford this with businesses to run, videos to edit, and things to do. Now, I don’t worry: the bootloader shows me a list of working configurations I can time travel to.

Ease of experimentation#

With flakes, I can try new configurations, add in packages (even easier with ephemeral nix shells which we will get to) and not pollute my configuration with any files that I don’t explicitly want.

Fix once, fixed forever#

I wanted to get a VPN up and running a couple days ago, and when I did, I had an issue with firewall settings. Historically, I would have fixed this imperatively maybe taken notes on the steps to do so, forgot it, and have to re-learn it next time. With NixOS, I fixed the issue in my configuration,got it working, committed my changes, and now that fix will persist for all time as part of my infrastructure DNA. Nice.

No more configuration drift - solved ✅#

When you change settings in your dotfiles, you version control those changes and you’re laughing, right? To a degree - except for the imperative changes you have to make to change settings and enable system services etc. I always forgot changes I would make, even with scripts for auto-installing things, and over a year or more of running a system, you honestly forget what you have installed on it. Now, I can see exactly the packages on my systems, as well as settings, services, processes - everything slaps you in the face.

An example of this is setting up kmonad, my keyboard mapping software: classically, I have to go out and get the package from github (it doesn’t exist in Fedora’s repo), add my user to uinput group, pull in my configuration from github, and then hope it works.

In NixOS, this looks like this:

{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
kmonad
];
# Setup Kmonad
boot.kernelModules = [ "uinput" ];
services.udev.extraRules = ''
# KMonad user access to /dev/uinput
KERNEL=="uinput", MODE="0660", GROUP="input", TAG+="uaccess"
'';
# Add your user to the input group
users.users.joshua.extraGroups = [ "input" ];
}

And I have kmonad working from first boot; not just on this machine, but on any desktop/laptop I setup in the future. Is there upfront investment? Yes. Is this easier than remembering how to do set it up every fresh installation? Yes.

Make all your changes to your configuration.nix or flake (another post) - do nothing imperatively, and you will actually be laughing.

“Works on my machine!” - solved ✅#

NixOS provides a mathematical guarantee about system state through pure functional package management. This cannot be overstated - if I have a program that runs on my machine with hash `abc123`, it will run identically on your machine because we’re referencing the exact same thing.

The magic lies in the store paths: `/nix/store/hash-package-version`. Every dependency is cryptographically hashed based on its inputs, creating an immutable, content-addressed system. Dependencies don’t just “work” - they’re mathematically proven to be identical.

In a nix-shell, you enter a pure environment where every dependency is precisely specified: they are ephemeral, they come in and out of existence, and they work.

Consider this:

nix-shell -p python39 numpy
# Instantly drops you into an environment with Python 3.9 and NumPy
# Exit the shell - it's gone, no system pollution

Compare this to traditional package management: “Install Python 3.9 and NumPy” could mean dozens of different combinations depending on when you installed, what repo you’re using, what other packages influenced the resolution. With Nix, “install Python 3.9 and NumPy” has exactly one mathematical meaning. When using Flakes, this is locked as it would be in package.json or go.mod: the version is pinned and you get the same output everytime.

This is not just “works now but maybe not tomorrow” - in 5 years, the closure (dependency graph of everything needed to get to the working state) will work. This hash table is not just stating a package - it states every dependency needed to get that package working at that point in time.

Dependency Hell - solved ✅#

The way that Nix (the package manager) works is that it keeps copies of all installed program versions in the store (until deleted) - so you can have multiple versions of python installed and they don’t interact. NixOS takes “inputs” and does the work to get the generated “outputs”: so you do not need to worry about filling dependencies, this is handled for you

NixOS doesn’t manage dependencies, it reimagines how dependencies should interact.

Virtual and development environments solved ✅#

Ephemeral environments and scripts#

When writing scripts classically, you would need to make sure the dependencies that a script requires are installed on the machine. No longer. Write your scripts with a nix-shell call, and you now can run them anywhere nix runs.

You declare your environment in your script - so now they are truly portable across any machine running Nix.

See this shebang for adding packages to a nix-shell script (which is what all of my scripts are now):

#!/usr/bin/env nix-shell
#! nix-shell -i bash -p podman openssh curl coreutils gnugrep gnused gawk
# shellcheck shell=bash
set -euo pipefail

that’s right - you now never have to worry if you have a program or tool installed when writing a script. it’s done for you.

Development environments#

Think about python virtual environment hell. Then realize that nix solves it by creating a shell in any project with any and all dependencies. It is why you see so many github repos with a flake.nix file in them: because you can create an environment with very little effort so that you don’t even need to install packages on your machine anymore: they can live in the project and then go away when you don’t need them.

Consider this example of a nix-shell for a pythin project:

{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { nixpkgs, ... }: {
devShells.x86_64-linux.default = with nixpkgs.legacyPackages.x86_64-linux;
mkShell {
buildInputs = [ python311 python311Packages.requests python311Packages.pytest ];
};
};
}

Now nix develop drops you into a shell with Python 3.11, requests, and pytest - nothing installed globally, nothing conflicting with other projects. We clone the repo, run nix develop, and everyone that is working on the project is in an identical development environment.

No more “setup instructions” that plague README files. No more “install Python, create a virtual environment, activate it, pip install requirements.txt, pray” Just nix develop.

package management - solved ✅#

imperative vs. declarative. this is the question.

The fundamental shift from imperative to declarative package management is where NixOS is a full paradigm shift:

With traditional package management, you’re constantly fighting against entropy - packages get installed, removed, updated, and leave behind cruft. Dependencies conflict. Your system slowly drifts from its intended state.

NixOS flips this entirely. Your configuration.nix becomes the single source of truth. Want to install a package? Add it to your configuration and sudo nixos-rebuild switch. Want to remove it? Delete the line and rebuild. No surprises, nothing missing or added.

No more sudo apt install and getting a different package at different points in time, no dependency hell, no orphaned packages lingering in corners of your filesystem you didn’t even know exist. The system is what you’ve said it to be.

And you have 100 servers that you need to make identically, cryptographically the same? Copy the configuration file. Done. Every machine you spin up becomes identical, predictable, manageable. No Ansible playbooks that might work differently depending on the starting state. No Chef recipes that assume certain packages are already installed. No Docker images that work in staging but fail in production due to subtle host differences. This is the solution to holistic DevOps.

The philosophical shift#

NixOS is a return to first principles for me. It is the first machine I have run in many moons that just gets out of the way so that I can work on what I want to work on. And, while it changes the way you think about a computing system, thinking declaratively seems to be the way of the winds in recent times. It’s not about patching and bandaiding your way through system administration - it’s about designing the ideal system and having the computer conform to that vision.

I see this as computing as it should be: intentional, reproducible, and under your complete control. Every aspect of your system becomes deliberate rather than accidental. Your infrastructure becomes code, version-controlled and tested like any other critical system. It allows you to treat a computer less as a pet, and more like cattle: I care about the data on a machine, but the machine itself is expendable. If I lose my laptop, I can get another one, clone my public nix repo, and be back to where I was in 30 minutes flat.

For me, NixOS really seems to be the final resting place, the endgame of all distributions. Not because it’s perfect - it has rough edges and a steep learning curve, its documentation is miles wide but inches deep (but getting better!), the nix language could be a language that is utilised elsewhere (like Guile Scheme) - but even then, Nix and NixOS solve the fundamental problems that have plagued Linux systems since the beginning.

This is what mastery looks like in system administration: not memorizing commands or accumulating tribal knowledge, but building systems that work predictably and indefinitely. NixOS gives you the tools to achieve that level of control and understanding.

My journey to NixOS has taught me that the endgame isn’t about “the most features”, the “bleeding edge”, or “stability”: because Nix offers that. For me, it has been about coming to find the system that lets me focus on what actually matters while handling the complexity underneath with precision that is generational, identical, and reproducible.

NixOS isn’t perfect, but it solves more problems in computing than anything else. It is the “emacs of operating systems” - and for me, that is perfect.

Resources#

You will be doing a lot of reading when you first start on the Nix train. It is very different from classical Linux, and the community is enthusiastic (as I am). Here are some of the best resources to get you rolling:

As always, God bless, and until next time.

If you enjoyed this post, consider supporting my work by Buying me a Coffee, Checking out my book, or sending me an email to tell me what you think.