• she/her

Principal engineer at Mercury. I've authored the Dhall configuration language, the Haskell for all blog, and countless packages and keynote presentations.

I'm a midwife to the hidden beauty in everything.

💖 @wiredaemon


discord
Gabriella439
discord server
discord.gg/XS5ZDZ8nnp
location
bay area
private page
cohost.org/newmoon

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/gcc are build-time dependencies of the hello package that are not protected by the GC root created by the hello build.

There's a simple solution to this problem that is a strict improvement in essentially every way:

  1. Enable keep-outputs = true in your Nix configuration (e.g. nix.conf)

  2. 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.


You must log in to comment.

in reply to @fullmoon's post:

Is there no way to keep a root for the derivation via nix config (rather than having each dev run a command in each worktree)? E.g., something like keep-failed? Maybe you wouldn’t want to set it globally, but how about in a flake?