Note: This is the abridged version of a blog post I'm working on.
Nix provides some default support for protecting builds with GC roots so that they don't get garbage collected.
As a concrete example, if I run:
$ nix build nixpkgs#hello
… that will create a ./result symlink that protects the hello package and its dependencies from being garbage-collected until I delete the ./result symlink.
However, there are two limitations to this approach:
-
The GC root is only created if the build succeeds
If the build fails then all intermediate build products are vulnerable to garbage collection
-
This GC root only protects run-time dependencies
That means that garbage collection can still remove build-time dependencies, which can be expensive to recreate
For example,
clang/gccare build-time dependencies of thehellopackage that are not protected by the GC root created by thehellobuild.
There's a simple solution to this problem that is a strict improvement in essentially every way:
-
Enable
keep-outputs = truein your Nix configuration (e.g.nix.conf) -
Create a GC root for the derivation instead of the build product
For example, if we wanted to create a GC root for the hello package's derivation, we'd run:
$ ln --symbolic "$(nix path-info --derivation nixpkgs#hello)" /nix/var/nix/gcroots/hello
… and now all build-time dependencies of the derivation are protected from garbage collection, even before the build begins. That means that if the build fails then any build-time dependencies that were built or downloaded along the way remain protected by that GC root until you delete it (but only if you remembered to enable keep-outputs = true).
That's it. That's the entire tip.