Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Choose where a system is built

Building a NixOS system needs memory and CPU. The machine that will run the system is often not the best machine to build it — and sometimes cannot build it at all.

deployment.buildOn decides this per host.

The options

buildOnEvaluates onRealizes onUse when
auto (default)resolvedresolvedLet NXD decide from the target and available builders
builderbuilderbuilderA capable machine builds; only the result ships
localorchestratororchestratorYour workstation can produce this system
targettargettargetThe target has ample CPU and memory
instantiatedorchestratortargetThe target cannot evaluate, but should hold the result
nativetargettargetForce target-native even under low memory
crossorchestratororchestratorCross-compile, e.g. ARM64 from x86_64

buildOn = "builder" requires deployment.builder = "user@host".

The low-memory case

Evaluation — working out what to build — can require more memory than a small machine has, before a single package is compiled. A 1 GB VM will often be OOM-killed during evaluation.

Set lowMem:

deployment = {
  lowMem = "yes";
};

With lowMem = "yes", a target build is automatically upgraded to instantiated: the orchestrator performs the memory-hungry evaluation, and the target realizes the reviewed derivation into its own store. The small machine never holds the build plan, but the finished system is still assembled where it runs, so no large closure transfer is needed.

NXD validates that the derivation produces the reviewed output, so this is not a weaker guarantee than building anywhere else.

Declare builders explicitly

Use builderBySystem to declare which builder serves which system type:

deployment = {
  buildOn = "builder";
  builderBySystem = {
    "x86_64-linux" = "deploy@utils";
  };
};

NXD deliberately does not inherit ambient builder configuration from /etc/nix/machines. A build that silently used whatever the workstation happened to have configured would make placement invisible and unreproducible between operators. Declaring builders in the repository keeps placement part of reviewed configuration.

Confirming what happened

Provider progress reports both the configured and the resolved placement:

✓ [medo] build placement configured=auto builder=deploy@utils

If auto resolved somewhere unexpected, this line says so.

A note on evaluating locally

Evaluating on your workstation instead of a Linux builder is a mitigation for memory pressure, not a speedup. Local evaluation on macOS in particular is slower than evaluating on a Linux builder. Choose it when the alternative is an OOM kill, not to make deployments faster.