Oh gosh oh gosh. I don’t know if I’m ready.

It’s time for Part V: Advanced Topics.

Chapter 16. Remote Builds

I try not to panic.

We open on an example.

$ nix ping-store --store ssh://mac

Curious, I try out my NixOS VPS, who is named claudius:

$ nix ping-store --store ssh://claudius

$ echo $?

Okay? It’s nice to see nix commands in this section. I think it’s the first time!

It shows me an example of how to build a Mac package on a Linux box. I reverse it, because I am on a Mac.

$ nix build \
  '(with import <nixpkgs> { system = "x86_64-linux"; }; runCommand "foo" {} "uname > $out")' \
  --builders 'ssh://claudius x86_64-linux'
error: unexpected end-of-file
builder for '/nix/store/ybjbbry0qn7i5m7hnbk8xgss0xi2wnl5-foo.drv' failed with exit code 1; last 1 log lines:
  error: you are not privileged to build derivations
[0 built (1 failed), 58 copied (75.1 MiB), 5.3 MiB DL]
error: build of '/nix/store/ybjbbry0qn7i5m7hnbk8xgss0xi2wnl5-foo.drv' failed

Boo. Hmm. There’s nothing in the manual about this.

Let’s try something more real:

$ nix build \
  '(import <nixpkgs> { system = "x86_64-linux"; }).hello' \
  --builders 'ssh://claudius x86_64-linux'
[4 copied (31.6 MiB), 6.6 MiB DL]
$ readlink result
$ file result/bin/hello
result/bin/hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /nix/store/3wa1xwnfv8ada1za1r8m4vmsiz1jifqq-glibc-2.32-35/lib/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, not stripped

Okay, that works? That didn’t need permission? Huh?

I wonder if this is because I had already built hello on the remote machine, so nothing actually happened. I remove it and collect garbage. And then remember that I need to remove the gcroots, and collect garbage again. I do this on both my local machine and the remote machine, as a sort of superstitious tic because I don’t really understand what’s going on.

$ nix build \
  '(import <nixpkgs> { system = "x86_64-linux"; }).hello' \
  --builders 'ssh://claudius x86_64-linux'
[4 copied (31.6 MiB), 6.6 MiB DL]

Still works! Huh?

Why doesn’t the other thing work? I can run it locally without any trouble:

$ nix build '(import <nixpkgs> {}).runCommand "foo" {} "uname > $out"'
[1 built, 11 copied (4.5 MiB), 1.3 MiB DL]
$ cat result

Okay. Hmm.

$ nix build \
    '(import <nixpkgs> { system = "x86_64-linux"; }).runCommand "foo" {} "uname > $out"'
[25 copied (53.2 MiB), 11.9 MiB DL]
error: a 'x86_64-linux' with features {} is required to build '/nix/store/ybjbbry0qn7i5m7hnbk8xgss0xi2wnl5-foo.drv', but I am a 'x86_64-darwin' with features {benchmark, big-parallel, nixos-test}

Okay. That was a sanity check – and it did not work, as expected. Now another sanity check:

$ nix build '(import <nixpkgs> { system = "x86_64-linux"; }).hello'
[4 copied (31.6 MiB), 6.6 MiB DL]

Ohhhhh. I see. I’m getting this from the binary cache, aren’t I? Yes. That makes sense. That’s why the example uses a dynamic derivation – got it got it.

man nix-build has no hints about this. But man 5 nix.conf does: I think this is because my NixOS machine uses “multi-user” Nix, and it’s a whole thing. I learn that I should make a new build user. But, this being NixOS, I don’t remember how. I mean, I actually do – it’s really very nice to manage users and groups in NixOS, relative to “normal” Linuxes – but I’ll pretend that I don’t, for now.

Anyway. I will not bother setting this up right now. Maybe one day.

I read about the options. Highlights:

The “speed factor,” indicating the relative speed of the machine. If there are multiple machines of the right type, Nix will prefer the fastest, taking load into account.


To build only on remote builders and disable building on the local machine, you can use the option --max-jobs 0.

Maybe also neat.

Chapter 17. Tuning Cores and Jobs

This isn’t really… this is an incredibly short chapter. It says what you’d expect. You can configure cores and jobs, in the ways you’d expect.

It is up to the derivations' build script to respect host’s requested cores-per-build by following the value of the NIX_BUILD_CORES environment variable.

Nothin' magic here.

Chapter 18. Verifying Build Reproducibility with diff-hook


this hook is only executed if the results are not the same, this hook is not used for determining if the results are the same.

Semicolon police.

I can run a custom program if a build doesn’t match? Why would I do that? Set it up to send me an email, or something? I dunno.

I can pass --check to nix-build to try re-building a derivation that I already have, and see if it produces the same output. Neat.

Using --check with --keep-failed will cause Nix to keep the second build’s output in a special, .check path

Okay; that’s neat. And I learn that .check paths will always be garbage collected.

I also learn that I can set up Nix to automatically build derivations multiple times and only succeed if the build is deterministic. That’s neat.

Chapter 19. Using the

That is… that is the chapter title. I didn’t truncate it.

It seems to be about uploading build results to S3?

No: this chapter is referred to as “Using the post-build-hook” elsewhere in the manual. I guess the monospace formatting doesn’t work in a title? But it worked in the last chapter. Huh. Whatever is generating this manual seems to have choked?


The post build hook program runs after each executed build, and blocks the build loop. The build loop exits if the hook program fails.

Okay. So don’t do network stuff, if you don’t want to block on network stuff. I’m not gonna read about S3 because I’m not gonna use S3.

The example shows that Nix has support for s3:// paths in substituters. Weird. Never seen that before. Never really had to use S3! I mean, not in like… eight years? Be a shame to break the streak now.

Some more nix commands I’ve never seen before in that example, though:

nix sign-paths --key-file /etc/nix/key.private $OUT_PATHS
exec nix copy --to 's3://example-nix-cache' $OUT_PATHS

I also see nix store --realize /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example, which appears to be a way to get paths in the store from the cache?

$ nix store --help
error: 'store' is not a recognised command
Try 'nix --help' for more information.

Sad trombone sound.

man nix-store says nothing about --realize, so I have no idea what command is supposed to mean or be.

But nix-store --realize seems to be a command, just undocumented in the man page?

$ nix-store --realize /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
don't know how to build these paths:
error: build of '/nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example' failed

I think that’s a first.

Ah. Ha. No. --realize exists, but it’s documented in the man page as --realise, so my search didn’t find it.

The operation --realise essentially “builds” the specified store paths.

Okay. Hmm.

Anyway, we can do stuff any time we build anything, and we learn how to sign and configure our own binary cache – which is, really, pretty cool, even though I did not do it.

  • Is there any difference between nix-build and nix build?