Purity and Reproducibility¶
Overview¶
In Nix, purity means evaluation and builds should not depend on undeclared ambient state—system libraries on $PATH, impure environment variables, or untracked network access. Given the same declared inputs, Nix aims to produce the same store paths.
Reproducibility is the goal: anyone with the same inputs can obtain the same artifacts. Purity is how Nix pursues that goal. Hermetic builds—sandboxes, fixed inputs, isolated builders—are the main mechanism; see Why Nix for how this fits the broader design.
Details¶
What “pure” means in practice¶
A derivation lists its inputs explicitly: sources copied into the store, dependency store paths, builder, and the environment variables the builder sees. During a build, the sandbox (when enabled) isolates the builder from the normal filesystem hierarchy so it sees only declared store inputs, a temporary build directory, and configured sandbox-paths. On Linux it also uses private namespaces; sandboxed builds other than fixed-output derivations get no network, which prevents undeclared fetches (see the manual sandbox setting). Sandboxing is available on Linux and macOS; sandbox defaults to true on Linux and false elsewhere per that setting.
Evaluation can also be impure—reading arbitrary host paths, depending on $HOME / NIX_PATH, or fetching without a content hash. Pure evaluation is a separate, eval-phase restriction: the pure-eval setting (flake evaluation turns it on by default; non-flake workflows can enable it, for example with nix eval --pure-eval) limits filesystem and network access to hash-pinned inputs and disables impure constants such as builtins.currentSystem and builtins.currentTime. That is related to build purity but applies before the builder runs; see Pure eval and impure.
Controlled impurity: fixed-output derivations¶
Some work genuinely needs the network (downloading upstream sources or vendored dependencies). Fixed-output derivations (FODs) are the controlled exception: the builder may use the network (on Linux, FODs are not placed in a private network namespace), but outputHash, outputHashAlgo, and outputHashMode fix the expected output in advance. If the fetched content does not match, the build fails rather than silently changing the closure.
Input-addressed identity vs bit-for-bit binaries¶
By default, derivations are input-addressed: the hash in the output store path is derived from the derivation and its inputs, so the same input graph yields the same path. That identity is what makes caching, sharing, and rollback practical.
Bit-for-bit reproducibility of every file across all hosts and compilers is a stronger property and is not guaranteed by input addressing alone. Timestamps, parallelism, toolchain differences, and platform-specific behavior can still change bytes even when the store path name matches the input hash. Nix’s model is reproducible enough for substitution and rollback: if inputs match, you get the same store object identity; producing identical NAR bytes everywhere is a separate packaging concern—see Reproducible builds audit.
Examples¶
Same inputs, same store path. Two machines build the same derivation with the same pinned nixpkgs and sources. Both realize the same /nix/store/<hash>-… path—not because they share /usr, but because the derivation and its closure are identical.
Undeclared impurity breaks reproducibility. A builder script reads /etc/ssl/certs or relies on $HTTP_PROXY without going through a FOD / impureEnvVars. One machine succeeds; another fails or produces a different result. Sandboxing surfaces this by failing closed when the host path is invisible.
FOD pins upstream content. A fixed-output derivation declares the expected digest before the builder runs (attributes from the Nix manual; a real fetch also needs name, system, builder, and a downloader—use nixpkgs fetchurl rather than inventing one):
# Marks the derivation as fixed-output. Needs network to realize;
# mismatch against upstream bytes fails the build.
{
outputHashMode = "flat";
outputHashAlgo = "sha256";
outputHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
}
If upstream changes the artifact, the build fails until outputHash is updated—the network was used, but the output remains fixed.
References¶
- Nix manual — derivations — declared inputs and builder environment
- Nix manual — advanced attributes —
outputHash*/ FOD vs input-addressed kinds - Nix manual —
sandboxsetting — hermetic build isolation - Nix manual —
pure-evalsetting — eval-phase purity - E. Dolstra, The Purely Functional Software Deployment Model (PhD thesis PDF) — historical design rationale; background only, not a normative spec for current Nix
See also¶
- Hermetic builds — sandboxes and fixed inputs as mechanism
- Why Nix — design motivation
- Derivation — the unit of build description
- Fixed-output derivation — controlled network fetch
- Pure eval and impure — purity during evaluation
- Store path — input-addressed path identity
- Reproducible builds audit — auditing bit-identical vs repeatable builds