Let’s talk about some of the issues with Nix and NixOS, and how Guix does these things better. I’ll say upfront that you shouldn’t expect tons of examples - this is a fairly quick writeup, though I might come back later to revise sections and add more points.
Guix uses so called build systems - these ensure consistency in how packages are actually built across different toolchains and language ecosystems.
- Each package ecosystem has its own build system. These define certain dependencies and standard procedures used for handling packages within that ecosystem.
- Examples would include the Maven and TeX Live ecosystems.
- This ensures consistency within these ecosystems.
- All of these build systems are in a single place (see points below) - this helps keep the different build systems consistent in behaviour.
- Combined these ensure global consistency in the approaches used for handling different toolchains across all the definitions.
- Nix does have build phases, and even something similar to build systems, but…
- These build systems aren’t documented anywhere, at least as far as I could tell.
- They are scattered all over
nixpkgs
.- This makes the entire point about consistency void.
- All Guix package definitions are written exclusively in GNU Guile - a Scheme implementation
- While system calls do need to be invoked for certain builds, it’s done exclusively with Guile too.
- There is a mature and well documented set of different build utilities used to do this.
- These also make package transformations more straightforward using the flexibility of Scheme macros.
- For example rather than calling a
sed
within a shell script like what Nix definitions sometimes do, Guix uses the proceduresubstitute*
instead.- This keeps build scripts consistent with a single set of build utilities and a single language.
- There is a mature and well documented set of different build utilities used to do this.
- While system calls do need to be invoked for certain builds, it’s done exclusively with Guile too.
- Now for the Nix language.
- It’s poorly documented.
- The tooling is lacking, in part because it’s used pretty exclusively for Nix.
- It isn’t particularly good as a DSL (note: domain specific language). Why?
- A proper DSL is not flexible enough for functional package management, so it was an uphill battle from the start.
- It’s too complicated - the main point of DSLs is to simplify configuration.
- Quote from the “inventor” of the language 1:
TLDR: the Nix language has all the problems of a general purpose language (namely too much expressiveness, allowing people to build new abstractions that make it harder for other people to understand their code, and making evaluation slow), while not having the features you would expect from a general purpose language, and at the same time not having many domain-specific features (indeed string contexts are one of the few). So it’s not that great as a DSL or a GPL.
- It isn’t good as a general purpose language either (no libraries, no interest in using it outside of Nix).
- There exist attempts to address these issues with different languages, for example Nickel has such aspirations.
- I recommend reading this blogpost, it goes over some of the issues of Nix.
- Guix addresses these issues by using a language that’s properly general purpose and more flexible with its very powerful macro system.
- Guix’s init system, GNU Shepherd is also written in Scheme, along with the entire CLI interface and every other part of the Guix system, aside from the daemon - further proving it’s capability as a GPL.
- Nix is also known for being rather difficult to debug (see discussion here).
- Recursion is used heavily - in practice this makes stuff like copying objects rather difficult.
- Infinite recursion can be difficult to debug and is rather easy to introduce - see below.
- https://nix.dev/anti-patterns/language
- Recursion is used heavily - in practice this makes stuff like copying objects rather difficult.
- Nixpkgs commits aren’t signed - see NixOS/rfcs#100 (at least it’s being worked on… slowly).
- Overall quality of definitions in Nixpkgs isn’t always great - many R packages are autogenerated and thus broken.
- Many packages also aren’t bootstrapped properly, instead patching and repackaging
.deb
packages and the like. - These is a ton of patching going on to resolve FHS incompatability issues (Guix is also affected by this).
- Many packages also aren’t bootstrapped properly, instead patching and repackaging
- Nixpkgs is unreliable - this speaks for itself…
First of all grafts. What are they?
Grafts are Guix’ way of not rebuilding the world when an important security is rolled out. Basically, they allow you to build and link against old versions of a library while running the program against a new one. Traditional distros do that all the time and you don’t even notice, but on Guix you actually have two versions of that library still lying around. The ungrafted one and the grafted one. – Guix documentation
To my knowledge Nix has no such thing.
- Thank you to user dali99 for correcting me here - Nix does in fact have a mechanism similar to Guix’s grafts, however it isn’t used and it doesn’t seem recursive application is supported either.
Nix also doesn’t have an equivalent to ~guix pack~.
- https://guix.gnu.org/manual/en/html_node/Invoking-guix-pack.html
- https://guix.gnu.org/blog/2023/the-filesystem-hierarchy-standard-comes-to-guix-containers/
- Nix does in fact have
nix bundle
now as a part of the flake CLI (thanks again to dali99 for the correction).
- As I have mentioned multiple times before, the Nix documentation is infamously bad, see the blogpost below.
- The Nix manual is also comparatively poor compared to what Guix offers (which includes a “cookbook” full of examples)
- nix-env is considered bad by a big part of the community (1) (2).
Yet the documentation doesn’t mention any of it’s shortcomings and it doesn’t exactly have a great replacement.
nix-env
has a problem with RAM usage, it’s extremely inefficient.- What should we use instead?
flakes
are experimental and not all too well documented (1).nix profile
isn’t quite a 1/1 replacement and lacks documentation (1).home-manager
? Has it’s own issues. It’s also not well documented.- besides that, some people don’t want to use it - using an entire complex system like this to replace
nix-env
is silly.
- besides that, some people don’t want to use it - using an entire complex system like this to replace
- Many tools are considered deprecated, yet are kept around for legacy compatability and referenced in the documentation, or they don’t have good replacements (see
nix-env
section above).- Searching for packages can be done using
nix-env
- but it’s extremely slow as it lazily evaluates the entire package database.- There’s a new experimental method, it’s better as it uses caching but it’s far from perfect.
- Guix has a proper search implementation.
- The CLI experience is bad (this issue is closed, but it’s far from resolved in practice) - many different tools all behaving differently, all with their own pitfalls and “gotcha”s.
- Searching for packages can be done using
WARNING: opinionated conclusion!
Overall Nix is a very flawed piece of software and far inferior to Guix. Years and years of technical issues plague the project and there seems to be little interest in actually resolving these issues. Guix is comparatively much newer, yet the UX is much better and there are constant improvements in many areas. It also has the advantage of being built from the ground up with a clear design mind.
This isn’t the complete document, I might come back and add more - for now I have already spent too long on this, and I think I outlined many of the issues rather clearly. If you find incorrent information please contact me and I’ll be happy to correct myself :)!