Nix Remote Builds for Architecture-Consistent Hermetic Outputs
Declared inputs make distributed builds reproducible across architectures.

Nix remote builds bring the pure-functional build model to other machines and target architectures. They move compilation to another machine and base the build on the declared input closure instead of the state that has built up on that machine. This gives distributed builds the same basis and makes their outputs easier to trace, audit and deploy.
Why conventional builds break across machines and architectures
Conventional build systems often depend on more than the source tree. They also use the system libraries, compiler versions, environment variables and filesystem state already on the machine. Dependency resolution is therefore partly implicit because tools search library paths and PATH as they run. Two machines with different packages installed can build the same source and produce different binaries. The machine becomes an undeclared input.
Cross-architecture builds make that ambiguity harder to control. Building an aarch64 artifact on an x86_64 host with conventional tooling means managing the sysroot by hand, and the environment that produced the binary may never be fully spelled out. Consequently, “it built in CI” does not establish that the production artifact is bit-for-bit equivalent to what a developer tested. The same uncertainty complicates an audit because the source alone cannot explain the output. The missing foundation is a way to distribute multi-architecture builds without relying on shared mutable state.
How Nix's pure-functional model eliminates host-sensitive state
Nix treats a build as a function of an explicitly enumerated set of inputs. Those inputs include source content, the build script, the compiler, flags and all transitive dependencies. Malka & Zacchiroli describe how a cryptographic hash of build inputs determines the package’s store-path identity. Changes that conventional tooling might take in without notice become changes to the declared build.
The sandbox enforces that boundary by restricting a build to declared files and denying network access. An undeclared dependency therefore causes failure rather than silently entering through the host environment. Fixed-output derivations handle external fetching by recording the expected output hash in advance and rejecting content that does not match. This bounds the exception instead of giving ordinary build steps unrestricted access to changing external content. The store path then provides a common identity for the specified build across machines, although an input-derived identity should not be confused with independent proof of the output’s bytes. The pure-functional model establishes the conditions for reproducibility while leaving its limits open to examination.
What remote builds add to the pure-functional model
The client first evaluates the Nix expression and produces a derivation, which formally describes the build. It then sends that derivation and the complete input closure to the remote builder. Because the closure contains the store paths the build requires, the builder does not need a copy of the client’s mutable working environment.
The remote builder runs the derivation just as a local build does, sandboxed and network-isolated. It cannot observe the client’s filesystem or borrow its ambient environment. The remote builder returns the result under the store-path identity determined by the declared inputs, and a binary substituter can satisfy later requests for that path from a cache. Reuse therefore follows build identity rather than a guess that two machines look sufficiently alike. In the pure-functional model, the same closure describes the same computation wherever it runs. A heterogeneous fleet consequently needs no privileged machine whose accumulated state defines the correct result.
How architecture targeting works across remote builders
Machine independence means that each architecture-specific build has an explicit description whose identity is independent of arbitrary host configuration, even when binaries differ across target architectures. A single Nix flake can enumerate build goals for every target platform, while the remote-build protocol routes each derivation to a builder capable of producing it. The flake author can express those goals without maintaining separate toolchain configurations for each target. Architecture becomes part of the build specification rather than an informal property of a CI runner.
Cross-compilation uses a toolchain that produces code for a different target, whereas emulation allows the target environment to run on another architecture. Emulation carries a real performance cost, but pre-built aarch64 substitutes from the public cache can avoid compiling the entire closure from source. Building on a native remote machine is another route, and the nix-community project has added a high-core-count Ampere aarch64-linux builder to its infrastructure. None of these routes is universally preferable. Their common foundation is that each architecture-specific artifact remains bound to its declared input closure and can be traced through the derivation graph.
Why the hermetic build model is the correct foundation for supply chain integrity
Supply chain integrity depends on explaining the steps from source to the binary that runs. If a build can silently draw on undeclared libraries or changing network content, that explanation is incomplete before any provenance document is written. Hermetic builds address the gap at execution time by bounding the files and external content that can enter the process. Cryptographically derived identities then give those declared inputs stable references. This makes independent verification tractable because the claim concerns a specified computation.
The practical payoff is clearest during CVE response. When deployed artifacts are mapped to their input closures, finding deployments that include a vulnerable dependency becomes a lookup through those identities. That is a stronger basis for impact analysis, but it does not make the builder or cache automatically trustworthy. Zwinger’s 2026 Aalto thesis identifies limits including trust in substitutors and problems with granular incremental builds. An input-derived store path alone does not prove that a compromised builder followed the declaration. The bootstrap seed also remains a trust boundary, because the minimal binaries used to begin building require verification through bootstrappable build techniques that are still maturing in the Nix ecosystem.
Generating auditable SBOMs and SLSA provenance from Nix derivations
A declared transitive input closure gives SBOM generation a source of dependency information within the build model itself. Tooling can walk the derivation graph instead of asking developers to reconstruct dependencies after release. The sbomnix utility accepts a Nix flake reference or store path and generates CycloneDX and SPDX documents. In contrast, an image-centric scanner must infer installed components from filesystem evidence. A graph-derived SBOM can therefore be a first-class build output.
This foundation also supplies declared build information relevant to supply chain provenance, although an SBOM and provenance serve different purposes. The existence of a derivation does not by itself establish that a pipeline satisfies external provenance requirements. The NixOS Software Provenance Team has a mandate to improve provenance and supply chain tracking in Nixpkgs and support infrastructure for high-quality SBOM documents. The 2026 conference framing describes bridging Nix/Nixpkgs and SBOM standards as imperative for the ecosystem, signalling work still to be done. CISA, the NSA, the FBI, and international partners published the 2026 Minimum Elements for an SBOM on 29 July 2026, updating and replacing the NTIA 2021 document. It covers open source, AI software and software as a service, so all these ways of delivering software need accurate dependency records.
How remote builds and hermetic environments behave in CI/CD pipelines
In CI/CD, the input closure takes over from runner configuration in choosing the build tools. When local development and CI use the same declared environment, differences in their installed compiler or library versions no longer need to affect the build. Nix Flakes lock external inputs at evaluation time, and a committed flake.lock records those selections for both contexts. The lock file serves as the reproducibility contract for the external inputs. Along with the project’s build definitions, it keeps dependency changes in view in the repository instead of hiding them in work done to maintain runners.
Binary caches make that discipline practical at team scale. If a requested derivation already has a cached result, the runner can retrieve it. Remote services can provide the remaining execution capacity without changing the declared-input model. nixbuild.net operates as a drop-in Nix builder, with each build in an isolated, virtualized sandbox that has no network access and contains only declared build inputs. It shares results when the input closure matches, provides nixbuild-action for GitHub Actions and can serve as a Hydra worker with a large number of concurrent jobs. The operational division is clear, with repository definitions selecting inputs, remote builders executing derivations and caches avoiding repeated work.
Producing minimal, verifiable OCI images as a deployment artifact from Nix builds
The same closure can become a container deployment artifact through the dockerTools.buildImage function in Nixpkgs. Rather than assembling an image from an ambient build environment, the function creates an image compatible with container tooling from declared Nix packages and their closure. Its contents can therefore be traced back to the derivation that produced it. Image-layer reuse follows the declared inputs instead of depending on informal similarities between build steps. This carries the build model into the artifact format used by existing container workflows.
Minimality follows from what the closure includes. An image whose closure does not declare a shell, package manager or extra system libraries can omit them without relying on manual Dockerfile discipline. The openDesk Edu project migrated 78 services from Helmfile and Dockerfile builds to NixOS-defined containers, with Grype vulnerability scanning, Cosign image signing and SBOM attachment in the same pipeline. For aarch64 images built from an x86_64 CI runner, routing execution to a remote native builder also avoids cross-compilation complexity at the image layer. Kubernetes still consumes OCI images, so this model complements container deployment. The change is in how the image’s contents are specified and traced before deployment.
What the hermetic remote-build model means for platform engineering teams
For platform engineering teams, the central responsibility shifts from maintaining equivalent machines to distributing explicit environments. Versioning the toolchain in the repository gives developers, CI jobs and agent sessions a shared description of the tools they need. Platform teams can publish environments with names and versions that consumers pull when they need them. Each version’s input-closure identity gives rollback an exact reference for the platform’s declared-environment contract, without the need to work out which dependencies were chosen before.
AI coding agents are another consumer of that contract. A shared Nix devShell gives an agent the project’s declared tool versions instead of letting an environment put together for a separate session choose them. The numtide/llm-agents.nix flake packages AI coding agents as Nix derivations, while the separate mcp-nixos tooling exposes NixOS packages, configuration options and version-history lookup to agents.


