Is NixOS truly reproducible?
What “reproducible” means in NixOS
- Several commenters emphasize two notions:
- Bitwise reproducible builds (identical output bytes).
- Reproducible environments (same inputs, toolchains, configs).
- Nix is seen as very strong at the latter: exact dependency graph and sandboxed builds, but bit-exactness still depends on upstream build determinism.
- Some argue Nix historically used “reproducible” in a looser, “repeatable builds with the same inputs” sense, whereas today the term usually implies bitwise identity.
Current state and limits of reproducibility
- A study cited in the article: nixpkgs reproducibility rose from ~69% (2017) to ~91% (2023).
- One critique: the absolute number of non-reproducible packages (~5k) hasn’t really dropped; percentages improved mainly because the package set grew.
- Causes of non-determinism mentioned:
- Timestamps in archives/JARs, lack or misuse of SOURCE_DATE_EPOCH.
- Parallel compilation and thread scheduling (output order differences).
- Uninitialized data in binaries.
- Build tools that depend on system time or environment (Java, Erlang in older days).
- Some note you can often “paper over” issues with post-processing (reset timestamps, normalize archives).
Nix vs Bazel, Debian, Arch, Guix, others
- Debate around Bazel:
- Pro-Bazel side: sandboxing, network blocking, hermetic toolchains for many languages, reproducible Java/C++ builds if toolchain fixed.
- Critique: sandboxing/network isolation and hermetic toolchains are often opt-in or partial; default toolchains may use host headers; not always hermetic by default.
- Nix is argued to enforce stronger hermeticity by default: own toolchains, host FS hidden, tightly controlled network.
- Debian and Arch also have strong reproducible-builds efforts; Debian tracks ~37k packages, Arch uses rebuilderd. One view: at this point most distros converge because real issues are in upstream build systems, not the package manager.
- Guix’s strict FOSS, build-from-source stance is seen as a prerequisite for complete from-source reproducibility but also more restrictive for users.
Binary blobs and policy
- Binary-only / unfree packages can’t be fully reproducible from source.
- Nixpkgs tracks license and source provenance and by default avoids evaluating unfree packages, but still includes them; some see exclusion (as in Guix) as ideological rather than technical.
- Others argue even with blobs, having the rest of the graph reproducible is still valuable for supply-chain verification.
Monitoring, metadata, and possible features
- There is a Nix reproducibility project and automated testing, but not continuous monitoring “at nixpkgs scale” yet.
- Suggested features:
- Mark packages as reproducible/non-reproducible in metadata; allow a “only reproducible” flag similar to
nonfree. - Propagate non-reproducibility transitively through dependency graphs.
- Community-driven telemetry: hash (inputs → outputs) pairs from many users to detect cohorts and outliers (“build chromatograph” idea).
- Mark packages as reproducible/non-reproducible in metadata; allow a “only reproducible” flag similar to
- One caveat: you can only definitively prove non-reproducibility; proving determinism is hard without formal methods.
Trust, supply chain, and the intensional store model
- Several discuss that reproducible builds only help if someone is actually comparing hashes across independent builders.
- Today, most users just trust the main binary cache; that makes it a high-value target.
- Proposed direction: use Nix’s formal build descriptions plus:
- Multiple builders attesting to outputs.
- Policies like “two independent attestations must agree” rather than a single trusted builder.
- Intensional store model (content-addressed Nix store) is mentioned:
- Hash paths by outputs instead of build instructions.
- Better deduplication and can skip rebuilds when outputs are unchanged.
- Can support stronger supply-chain properties, but you still need to trust signatures mapping input hashes to output hashes.
Runtime state vs system configuration
- One user equates reproducible with “immutable” and reports breaking NixOS by cycling desktop environments.
- Others clarify:
- NixOS makes system configuration (builds, /etc contents, etc.) reproducible/roll-backable, not user home directories or runtime state.
- Desktop environments and apps still write dotfiles and mutable state; to get closer to immutable systems you need patterns like:
- Impermanence-style setups (wipe local changes at reboot).
- Containers/VMs or ephemeral
nix runenvironments.
- NixOS is compared to “Ansible + Docker in one system”: declarative host config and build envs, but not full runtime isolation like containers or Flatpak.
Practical benefits and criticisms
- Supporters highlight:
- Very high reproducibility out of the box; easy local verification:
nix build ...; nix build ... --rebuildand compare. - Huge package set where reproducibility has been pushed much further than many thought feasible.
- Very high reproducibility out of the box; easy local verification:
- Skeptics point to:
- Usability and complexity costs (“right idea, wrong abstraction”, “nightmare” experiences).
- Persistence of a hard core of non-reproducible packages.
- The fact that ultimate guarantees still depend on upstream compilers and build systems being deterministic, which Nix cannot enforce.