~/ ~/documents ~/software ~/pictures github (opens in new tab)

Remote Nix Builds & Distributed Caching

Offloading heavy compilation to a dedicated remote build machine and sharing build artifacts across devices transforms the Nix development experience.

For quick, one-off builds on a remote host over SSH without modifying your system configuration, you can point the Nix store flag directly to a remote machine:

nix build --eval-store auto --store ssh-ng://nix-builder@host ...

Or copy closures manually between remote stores:

nix-copy-closure --from nix-builder@host /nix/store/...

While ad-hoc commands work well for temporary tasks, NixOS natively supports declarative distributed builds via nix.distributedBuilds and nix.buildMachines. On the build server, set up a restricted builder user:

users.users.nix-builder = {
  isNormalUser = true;
  description = "Nix remote builder user";
  openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5..." ];
};

On client machines, configure nix.buildMachines to delegate builds automatically over SSH:

nix = {
  distributedBuilds = true;
  buildMachines = [
    {
      hostName = "builder.internal";
      sshUser = "nix-builder";
      sshKey = "/home/dom/.ssh/id_build_key";
      systems = [
        "x86_64-linux"
        "aarch64-linux"
      ];
      maxJobs = 4;
      supportedFeatures = [
        "nixos-test"
        "benchmark"
        "big-parallel"
        "kvm"
      ];
    }
  ];
};

When building locally, the Nix daemon transparently forwards derivations requiring specific resources (big-parallel, kvm, or secondary architectures like aarch64-linux) to the remote builder. If you need to bypass remote build servers temporarily (e.g. when offline or troubleshooting), pass --builders "" to force the build locally:

nix build --builders "" ...

To share build artifacts across multiple machines on your network, pair distributed builds with Harmonia, a high-performance Nix binary cache server written in Rust that queries the local store directly and signs derivations on demand:

services.harmonia = {
  cache.enable = true;
  cache.settings.bind = "127.0.0.1:5005";
  cache.signKeyPaths = [ config.sops.secrets."services/harmonia/sign-key".path ];
};

On client machines, configure the private cache as a trusted substituter in Nix settings:

nix.settings = {
  substituters = [ "https://cache.internal" ];
  trusted-public-keys = [ "cache.internal-1:..." ];
};

If you ever need to bypass binary substituters and rebuild directly from source (e.g. to verify build reproducibility or when a cache server is unavailable), pass --option substitute false:

nix build --option substitute false ...

This workflow automates remote build execution, speeds up builds with instant artifact substitution, and keeps network traffic secure over SSH and signed cache outputs.