home..

Nix Post

linux nix

My Opinions on NixOS

1. The package manager

The Nix package manager was initially devised in a PHD Thesis for Utchrect University. It is, both in theory and in practice, the most robust package management system in existence, hosting more useable packages than even the prolific AUR.

pkgs-graph

What everyone else does

Arch (and most rolling release distros) share common, dynamically linked libraries in .so files in various /lib folders accross the system. Old libraries generally fall out of scope quickly, and if required, must be manually sourced among sketchy tarballs accross the internet. This means every single package must be kept up-to-date with all common libraries, lest it be labeled broken and eventually drop out of the AUR. All of this leads to fairly significant overhead for the maintainer, let alone any upstream developers. In my experience with Arch, the “only bleeding edge” mentality led to some package being broken almost every time I performed a system update (which, according to the Arch ideology, should be every time a new package is installed). That experience led to a feedback loop, where I would wait longer to perform a system update, and more things would be broken. Sometimes, this would be intentional, other times it would be because I didn’t have time to fix whatever package broke last time (it doesn’t help that pacman aborts an update if one package is broken). This rolling-release model is great for developers who need or want the bleeding edge, but kind of sucks for people who just want a working operating system.

Debian, Redhat, and their respective children1 generally use a much stabler system of release for their packages. Generally, they use a fixed-release model for their system updates (at a period of 6 months to two years). While a release is being developed, all packages within that release are tested for interoperability and functionality. Essentially, every six months or so, the entirety of the “stable” branch of the given package repository (accessed by apt, yum, etc.) is compiled and tested with the new libraries and kernel version. If you want more up-to-date software, you have to use an “unstable” branch – though it is still generally less up-to-date than rolling-release repos, while still not guaranteeing functionality2.

What Nix does different

Every package manager essentially does four things when installing a new package:

  1. It pulls a list of packages and their dependencies from its repository.
  2. It cross-checks your package and its dependencies against every package on your system.
  3. It pulls down everything your package requires in the form of a tarball.
  4. It uses some build scripts to compile all requires packages into binaries into their designated locations.

The Nix package manager hijacks step 4 in this system. Most package managers place binaries and libraries into unix-specified locations in the system (e.g. /etc/bin/ and /var/lib/). Nix installs every library into a hashed folder in the /nix/store/ directory3. The hashing means that every single version of a library, with even the smallest of changes, is treated as an entirely different package. This is the primary reason why Nix is so damn stable – it’s literally impossible to break a dependency, because dependencies are installed on a per-package basis. That’s not to say that there’s no inter-use of libraries; in fact, the freshness of nixpkgs is approximately equal to that of the AUR, so most packages still use the latest libraries. Additionally, every package must* be installed declaratively4, which makes it significantly easier to track the packages installed on your system.

Nix’s other big feature is the Nix programming language. The reason for its existence is simple: all build scripts are written in a programming language, and all programming languages get updated. This allows another potential method for a package to break: its build script no longer works. The Nix abstract’s solution to this was a proprietary language that’s function was to build compilers from the Nix store (cmake, meson, ninja, etc.), which then build the binary as usual.

2. Why NixOS?

NixOS takes the ideology of the Nix package manager and extends it to the entire operating system. Every single aspect of the system can be configured in the Nix language, from PAMs to systemd services to DEs. On top of that, through a software called home-manager, the Nix community has written translations for most package configurations into the Nix language (from neovim to hyprland, all of my dotfiles could be translated to Nix). This brings me to NixOS’s most powerful feature – the ability to completely copy a system from one device to another. This is basically impossible in any other OS. Dotfiles are easy to copy over, but what about a PAM configuration? What about your FSTAB? What about each and every one of your packages? The combination of Nix’s declarative package management, and its holistic approach to configuration means one file (or one directory if you’re not a masochist) can contain your entire operating system, or at least everything that makes it unique. In fact, NixOS intentionally separates hardware configurations (drivers, kernel modules) from software configuration to make this easier.

NixOS makes configuration easy. On Arch, every single piece of system configuration was its own adventure. Adding fprintd to PAM forced me to learn the PAM configuration language. It took me days to figure out how to enable hibernation. I wrote my own systemd service to auto-update Discord. All of these were useful experiences, and I don’t regret them – it’s just that every single one of them could be replicated with a single line in /nix/configuration.nix. That’s it. It’s not smarter, it’s not better, it’s just significantly easier in almost every regard.

3. Why don’t I like it

As I stated at the beginning of this spiel, Nix is the brainchild of a PhD thesis, and in my opinion, it was designed with that in mind. NixOS is a fully-fledged operating system that is wonderful for most of my day-to-day tasks, because most things just work™. That being said, under the hood, Nix is kind of a shitshow. The built in CLI utilities are written in a myriad of languages, many of which aren’t exactly optimized (read: slow). To amend this, community members have built their own, custom implementations of the same functionality. Despite its decades-long existence, Nix still feels like a side project created more as a proof of concept than a useable interface. There are so many features that aren’t part of Nix by default, but are so fundamental that >80% of users utilize them, namely home-manager and flakes. These tools do different things that I won’t get into here, but a recurring question in my mind when it comes to this OS is, why cater to the 20%?

In addition to the general mismanagement and disorganization of the Nix ecosystem as a whole, I have more personal gripes with it. First, development is genuinely painful. The lack of universal libraries means any software that I want to use (say, a C compiler, or python) isn’t meant to be added to the path. I have to explicitly declare what libraries and binaries I want to use in my development before entering the dev environment. It almost feels like spinning up an individual VM for every different language I use. Yes, people have made utilities to make this process easier – but its another example of the community fixing an issue that the Nix developers should factor in, given the fact that most of NixOS’s users are likely entrenched in the field of CS. Second, there’s just too many ways to do things. An OS configuration can and should be opinionated, but those opinions shouldn’t extend to every aspect of the OS itself. Perhaps the greatest example of this is the Nix docs, which are best described as confused. For such a unique system, Nix’s documentation is both lackluster and inconsistent. Seemingly every page proposes a completely novel way to perform any given task, in such a manner that makes it obvious there is no preferred way to do anything. If you compare the Nix docs to the Arch docs (which are, in my opinion, the gold standard), it’s clear where Nix falls short. Arch clearly outlines the best way to do something, then lists the alternatives. Nix doesn’t have a “best” way, and the method that’s described in a give doc is entirely at the whim of the editor. Basically, the official Nix docs read more like a forum than an actual manual – and, funnily enough, the best Nix manuals I’ve seen are community projects too.

4. What this means for me

I switched to NixOS because my Arch install felt too bloated. As many people do, I tried out a few other people’s dotfiles before settling on my own. This, along with various half-realized projects and seldom-used commands, meant that I simply had too many packages. Every system upgrade took too long, and too many things broke. I think Arch is meant to be a more lightweight OS, and I’m going to switch to it for development. Chances are, I’ll spin up a VM in my dormlab5 and ssh into that for all of my development needs.


  1. This includes the majority of common linux OS’es, including ubuntu, Pop!, mint, and many more

  2. I know less about this system, as I only spent a few months in kubuntu in my early days (and I’ve never really looked back). 

  3. My neovim editor lagged when I typed this, as it tried to add every subdirectory into my autocomplete buffer. There are a LOT of packages! 

  4. Declarative package management means every package must be explicitly written (declared) in a file. Npm’s package management is generally declarative. Most package managers are imperative, meaning package installation is dynamic (e.g. apt install [package], or yay -S [package]). 

  5. todo: write about that! 

Powered by Soopr   •  Theme  Moonwalk