Nix(OS) Considered Harmful
(Approx. 9 min read)
I really want to like Nix and NixOS. There are many genuinely amazing and intelligent ideas within the project, but every time I stop and consider recommending it to someone, I feel like I can’t give a positive endorsement of the project, even though the technology of Nix(OS) is incredible, and I hope someone better builds upon it someday.
What is Nix(OS)?
Many have never heard about this project, so a bit of explanation might not be remiss. Nix’s one sentence definition, as described by the main website1:
a tool that takes a unique approach to package management and system configuration.
but I don’t like this definition and it’s not really comprehensive. I’d suggest that when people refer to Nix and/or NixOS, what they really mean is:
A purely functional package manager that lets you declaratively manage system state and dependencies with the same configuration language.
We are already off to a bad start, given that it’s taken nearly a paragraph to even define what this thing is (more on this later). To clarify before I continue talking about it:
- Nix is a functional, Haskell-flavored DSL that lets you express configurations, specifically system state and package build scripts. It’s also confusingly the same name as the build tool that consumes this language.
- NixOS is a Linux distribution where Nix is the primary package manager. Nix scripts can configure nearly every part of the system in a declarative way; the system is built to the specification defined in the scripts.
- Its selling point is reproducible builds: any two Nix builds of the same Nix build script should result in byte-for-byte equivalent output with no changes2.
That last point cannot be understated. At the time of Nix’s release, nobody was doing this; it was a unique feature in the Linux world, and still kind of is today. Nothing achieves reproducible builds of both packages and systems at scale to the same extent Nix does, and a lot of its truly great ideas make it a one-of-a-kind piece of software.
Lost Potential
Nix is what happens when you have many great ideas in the hands of the wrong people. It and NixOS were originally designed by Eelco Dolstra in the early 2000s3, who had a lot of good ideas for how to fix the main problems with reproducible builds and Linux package management, but didn’t get around to fully realizing them:
- Builds should be content-addressable by the hash of their outputs, so that it’s obvious when they differ (ended up being based on hash of inputs due to rushed implementation)
- Nix scripts should output
.drvfiles, which are serialized graphs of their dependencies, making it possible to figure out exactly what their inputs are (ended up as a weird proprietary fork of the ATerm binary format, never documented) - Nix as a language is Haskell-inspired and thus can’t handle side effects which are needed for builds, so should have some standard library of monad-IO to handle this (never came about; the standard library for Nix is split between
nixpkgshelper scripts, the NixOS module system, and the virtual packagepkgs.libinnixpkgs) - There should be a clean and obvious way to pin state so that reproducible builds are easy to achieve (Nix tried this with the
flakefeature, but it never went anywhere, requires a compile-time flag to enable it)
The most painful part about Nix is that so often, the right idea was discovered, invented, and then died in committee because the community was unwilling or unable to adopt it. In particular, the community around Nix is one of the strangest I’ve seen in software development, because most who work on Nix only work on Nix-related projects, which is very strange for software that is primarily useful for building more software.
Flakes are the classic example of why this project still hasn’t taken off; before flakes, the way that inputs were declaratively managed is through NIX_CHANNEL, an environment variable listing GitHub URLs that Nix would checkout and then use as its package repo sources. Flakes allowed users to make a Nix file listing versions of package repositories and then generate a lockfile from them, so that specific versions of packages can be referenced and used in one’s builds. A great idea, but one that the Nix community continues to weirdly shutdown4 and doesn’t seem to be ready nearly anytime soon despite many advertising it as a selling point of Nix(OS) (just Google “nix flake” and you’ll see what I mean).
Problems and How To Fix Them
I’m not sure the current governance of the Nix project is the right direction. Eelco left a while ago and is seemingly doing his own thing now5 rather than engaging with the wider community, which is a warning sign that it might be beyond reform. In particular, most of the pain points with Nix(OS) stem from the same few issues. I like lists, so I’ll present it as a list.
Monorepo Problems
Nixpkgs, the primary package repository for Nix(OS), is bloated and enormous. It’s too big and too complicated, and relies on too much tribal knowledge to navigate comfortably. Nix as a language lacks a standard library, but with the virtual pkgs.lib package, they’ve created a bunch of scripts that act like them for the most annoying things to package. This is bad and makes the language much harder to learn & contribute to, increases maintainer burden, and ultimately makes it much harder to use.
Solution: Invest and stabilize Flakes, move more packages out of the core repository and into sub-repositories (Flakes would make this easy to do). Most distributions have a split between the core packages and the community/third-party ones (Fedora does this between its repos and RPMFusion, Ubuntu between core and galaxy, Arch has the AUR, etc); Nix(OS) should do similarly.
Bad Documentation
Nix is actively hostile to new contributors/users due to its famously awful documentation, its inconsistent and strange command line interface, and its famously cryptic error messages. It is also hard to learn how to write new packages and takes a lot of reading of Nixpkgs to figure out how to do so, which is hard because of aforementioned problems.
Solution: Documentation needs to be a higher priority. There are at least five different places for Nix(OS) documentation (Nix Pills, official NixOS Wiki, unofficial NixOS Wiki, Nix Manual, and nix.dev), which is absurd. They should be consolidated, ideally on the official website, with better navigation, and should provide recipes for the most common types of Nix package expressions people would want to write. Nix itself actually has been getting better error messages but they’re locked behind enabling the Flakes feature, which is yet another reason it needs to be made the default.
Nix is a Horrible Language
Of all the programming languages out there, Nix might be the least intuitive I’ve ever used. I’ve written Haskell before (completed the Learn You A Haskell for Great Good! book), which might be only reason I managed to figure Nix out. Nix’s lazyness and its weird blend of functional programming and terse bash build scripts make it very hard to debug when it just works. It is mostly a historical accident that Nix turned out this way, and it’s definitely too late to fix now, because too many people are used to it for the community to ever want to change it.
Solution: Need to start over with this one. There’s attempts at typed Nix and a rewrite into GNU Guile Scheme exists, but I wouldn’t recommend using it, it’s actually worse in a lot of ways. I suggest something more imperative, more like Lua, and with strong typing, and a lot less like Haskell, since it’s almost impossible to recommend Nix to non-functional-programmers.
Community & Governance
Like I said before, Nix is mostly run by non-programmers. Most Nix contributors are the Linux-desktop types who mostly run Linux because they have a commitment to doing things in the most obtuse way possible, and see Nix as a step up in “difficulty” compared to a distribution like Arch or Gentoo. People who want to actually use Nix in production are a minority within the community. I think Linux on the desktop is mostly a waste of time; Linux is for everything but the desktop6.
Solution: Again, start over. If Nix were governed by someone like David Heinemeier Hansson (Ruby on Rails) or Theo de Raadt (OpenBSD), the type of people willing to put their foot down and govern with taste and a strong set of opinions when needed, we would see far greater deployment today. Democracy is great, and works out for some larger projects (Linux), but Nix(OS) has been pulled in too many disparate directions and needs stronger focus, along with being mired in controversy7. A quick glance at the nix-community repository shows just how split that focus is.
Lamentation
Nix’s reproducibility is truly magical and I wish there was a better alternative to it. For all of its flaws, being able to git clone && nix build and get exactly the same binaries and even the same Linux systems is a superpower no other build tool is remotely close to right now for the same level of effort. I still use it for some systems, but I can’t recommend its use for new projects these days.
In particular, I think the Nix community is really missing out on some areas where it could be immensely valuable. High-Performance Computing is the niche I have in mind; most users on those machines are unable to get root to install more packages, and Nix’s reproducibility focus would make sharing code and building it a snap for complex projects like climate models. Someday, if nobody else builds upon these ideas, maybe I’ll try my hand at building a much simpler functional package manager for this niche, for these ideas feel far too good to just lie here and rot away under all of Nix(OS)’s cruft.
I think there is a way to get Nix’s magical features in a simpler way without all of the mistakes it made, and with a cleaner language. There are many attempts to fork Nix and take it in a new direction, and I’m sure there’ll be continued effort from the Nix Foundation to improve it, but they’ve ultimately doomed it to irrelevance. It is so hard to recommend despite how brilliant the ideas behind it are, and it’s a tragedy that it ended up in the way that it has.
https://nixos.org, taken right off the main page ↩︎
This isn’t universally true, and there’s a lot of work to be done on truly reproducible builds, but Nix is very helpful with regards to this and makes it much easier to achieve. ↩︎
Nearly a decade and still not done yet: https://github.com/NixOS/nix/milestone/27 ↩︎
The vast majority of people running Linux will never use it on their personal computers (no, Android doesn’t count), and to pretend otherwise is delusional. Desktop Linux is not to be taken seriously and is a very niche use case. For the vast majority of developers, macOS or WSL will be their development environment for decades to come. ↩︎
https://determinate.systems/blog/on-community-in-nix/. This article is a very good example of how not to handle controversy with a community’s relationship to corporate sponsors. ↩︎