The Nix Registry and a Local nixpkgs

2021-06-25

A short note on something that tripped me up as I started experimenting with nix flakes.

It's About Control

I have long relied upon a local checkout of the nixpkgs repository. I name that remote upstream, and I periodically git fetch upstream and point my local checkout to the upstream/nixos-unstable branch.

This local checkout is handy as it is very explicitly pinned to a particular revision, and trying out package updates or edits can be done in place without any fuss.

When trying nix-2.4pre from the nixUnstable package, I noticed that the nixpkgs flake is shown in nix registry list as simply pointing to github. That's not the kind of control I want. There are three registries: user, system, and global (listed here in decreasing priority). One can nix registry add to add a user registry entry that points to the local nixpkgs checkout. Or, to be more declarative, one can add to their NixOS system's configuration.nix:

{ config, pkgs, ...}:
{
  ...
  # Add the local nixpkgs checkout to the system flake registry
  nix.registry = {
    nixpkgs = {
      from = {
        type = "indirect";
        id = "nixpkgs";
      };
      to = {
        type = "path";
        path = "/path/to/local/nixpkgs";
      };
    };
  };
  ...
}

That adds the local checkout to the system registry. However, both versions of this exhibited an undesirable property: running anything with nix run was quite slow. One of the features of the nix tool as of the unreleased version 2.4 is better evaluation caching, so I was surprised at this setback. Note that if you don't touch your registries, the caching works beautifully and nix run is fast.

So here's a solution: leave that addition to the system registry so that it is what the nixpkgs identifier points to, then run nix registry pin nixpkgs. This stores a hash of the local checkout in the user registry so that commands like nix run are fast again.

When you update your local checkout, you can issue the nix registry pin nixpkgs command again to move the user registry pin to the currently checked out revision. If you are actively editing something in your nixpkgs checkout, remember to nix registry remove nixpkgs to remove the pin in the user registry so that the flake resolves to the nix code you're actively working on.