$ zimbatm

Recursive Nix experiment

Recursive Nix is the idea that Nix could be invoked from withing a Nix build. This is not my idea, it’s been around in the community. @edolstra (the creator of Nix) has been talking about it.

If a project is using Nix as a build system, it would be nice if those could be re-used when packaging the project for nixpkgs. At the moment this is only possible by using Import From Derivation (IFD).

TODO: ping me if you want me to explain more clearly why IFD is undesirable and the differences between IFD and recursive Nix.

This is a little experiment to see if it’s possible to implement Recursive Nix with today’s tooling.


Ok so the basic idea is that there will be one derivation invoking nix again in it’s build.

NOTE: build sandboxing is enabled and the nix-daemon is running.

The outer derivation: default.nix

with import <nixpkgs> {};
runCommand "recursive-nix" { buildInputs = [ nix ]; } ''
  nix-build ${./inner.nix} > $out

The inner derivation: inner.nix

with import <nixpkgs> {};
runCommand "inside" {} ''
  echo FOO | tee $out

Trying things out:

$ nix-build
error: creating directory '/nix/var': Permission denied


Nix needs access to /nix/var to talk to the nix-daemon socket.


The nix configuration allows to poke holes in the sandbox. This is not very desirable because it introduces impurities into the build and any user of that nix code will also need to have the same impurities configured.

Add /nix/var to the sandboxPaths:


extra-sandbox-paths = /nix/var

or add nix.sandboxPaths = [ "/nix/var" ]; to my configuration.nix

$ systemctl restart nix-daemon
$ nix-build
error: file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I), at /nix/store/j1hayqcvwcl2ci2fl04vnhpf41h5jklh-foo.nix:1:13


Ok so NIX_PATH is not set in the context of the build. Is it possible to pass it along?


Propagate the same version of nixpkgs to the inner build:


with import <nixpkgs> {};
runCommand "recursive-nix" { buildInputs = [ nix ]; } ''
  NIX_PATH=nixpkgs=${pkgs.path} nix-build ${./foo.nix} > $out
$ nix-build 
error: cannot open connection to remote store 'daemon': reading from file: Connection reset by peer



$ journalctl -u nix-daemon
Jun 17 15:42:59 x1 nix-daemon[6810]: error processing connection: user 'nixbld1' is not allowed to connect to the Nix daemon

/etc/nix/nix.conf has allowed-users = * adding @nixbld to the trusted-users doesn’t help.

Actually looking into the source code:


Since the user is part of the the buildUserGroup is it disallowed. The only way to fix this is to fork nix.


Forking nix and using Niv to import that into my system configuration:

$ niv add zimbatm/nix --branch allow-recursive-nix
Reading sources file
[0.8 MiB DL]
path is '/nix/store/j62jidqfyncj4xzxl947hvdby0prhfn9-b2068e762d4c7c107ccaf87346fef14879b16066.tar.gz'
Writing new sources file

and in the configuration.nix

nix.package = pkgs.nix.override {
  src = (import ./nix/sources.nix).nix;
  fromGit = true;

after a nixos-rebuild switch:

$ nix-build
these derivations will be built:
building '/nix/store/q4jxahknj5njrqpd8qv5qfxndmwpc7zi-recursive-nix.drv'...

$ cat /nix/store/9l599ms92ywmcqgdmm6anqw7yi0pr238-recursive-nix



Recursive Nix is possible today with a single line patch to Nix and a small configuration change. It’s possible but the next step is to think about if it’s desirable or not? If yes then we could maybe make those changes permanent.

Known issues

See also


Discussion should be happening over there: https://discourse.nixos.org/t/recursive-nix-experiment/3206

< EOF >
       \     (\/)
        \   (_o |
             /  |
             \  \______
              \        )o
               /|----- |
               \|     /|