Skip to content(if available)orjump to list(if available)

Is NixOS truly reproducible?

Is NixOS truly reproducible?

56 comments

·February 9, 2025

vlovich123

> Our most important finding is that the reproducibility rate in nixpkgs has increased steadily from 69% in 2017 to about 91% in April 2023. The high reproducibility rate in our most recent revision is quite impressive, given both the size of the package set and the absence of systematic monitoring in nixpkgs. We knew that it was possible to achieve very good reproducibility rate in smaller package sets like Debian, but this shows that achieving very high bitwise reproducibility is possible at scale, something that was believed impossible by practitioners4

I think people in this thread are focusing on the wrong thing. Sure, not all packages are reproducible, but the project is systematically increasing the percentage of projects that are reproducible while ALSO adding new projects and demonstrating conclusively that what was considered infeasible is actually readily achievable.

> The interesting aspect of these causes is that they show that even if nixpkgs already achieves great reproducibility rates, there still exists some low hanging fruits towards improving reproducibility that could be tackled by the Nix community and the whole FOSS ecosystem.

This work is helpful I think for the community to tackle the sources of unreproducible builds to push the percentage up even further. I think it also highlights the need for automation to validate that there aren't systematic regressions or regressions in particularly popular packages (doing individual regressions for all packages is a futile effort unless a lot of people volunteer to be part of a distributed check effort).

jchw

I think this debate comes down to exactly what "reproducible" means. Nix doesn't give bit-exact reproducibility, but it does give reproducible environments, by ensuring that the inputs are always bit-exact. It is closer to being fully reproducible than most other build systems (including Bazel) -- but because it can only reasonably ensure that the inputs are exact, it's still necessary for the build processes themselves to be fully deterministic to get end-to-end bit-exactness.

Nix on its own doesn't fully resolve supply chain concerns about binaries, but it can provide answers to a myriad of other problems. I think most people like Nix reproducibility, and it is marketed as such, for the sake of development: life is much easier when you know for sure you have the exact same version of each dependency, in the exact same configuration. A build on one machine may not be bit-exact to a build on another machine, but it will be exactly the same source code all the way down.

The quest to get every build process to be deterministic is definitely a bigger problem and it will never be solved for all of Nixpkgs. NixOS does have a reproducibility project[1], and some non-trivial amount of NixOS actually is properly reproducible, but the observation that Nixpkgs is too vast is definitely spot-on, especially because in most cases the real issues lie upstream. (and carrying patches for reproducibility is possible, but it adds even more maintainer burden.)

[1]: https://reproducible.nixos.org/

matrss

> The quest to get every build process to be deterministic [...] will never be solved for all of Nixpkgs.

Not least because of unfree and/or binary-blob packages that can't be reproducible because they don't even build anything. As much as Guix' strict FOSS and build-from-source policy can be an annoyance, it is a necessary precondition to achieve full reproducibility from source, i.e. the full-source bootstrap.

jchw

Nixpkgs provides license[1] and source provenance[2] information. For legal reasons, Nix also defaults to not evaluating unfree packages. Not packaging them at all, though, doesn't seem useful from any technical standpoint; I think that is purely ideological.

In any case, it's all a bit imperfect anyway, since it's from the perspective of the package manager, which can't be absolutely sure there's no blobs. Anyone who follows Linux-libre releases can see how hard it really is to find all of those needles in the haystack. (And yeah, it would be fantastic if we could have machines with zero unfree code and no blobs, but the majority of computers sold today can't meaningfully operate like that.)

I actually believe there's plenty of value in the builds still being reproducible even when blobs are present: you can still verify that the supply chain is not compromised outside of the blobs. For practical reasons, most users will need to stick to limiting the amount of blobs rather than fully eliminating them.

[1]: https://nixos.org/manual/nixpkgs/stable/#sec-meta-license

[2]: https://nixos.org/manual/nixpkgs/stable/#sec-meta-sourceProv...

0x69420

you can slap a hash on a binary distribution and it becomes "reproducible" in the same trivial sense as any source tarball. after that, the reproducibility of whatever "build process" takes place to extract archives and shuffle assets around is no more or less fraught than any other package (probably less considering how much compilers have historically had to be brought to heel, especially before reproducibility was fashionable enough for it to enter much into compiler authors' consideration!!)

sa46

> It is closer to being fully reproducible than most other build systems (including Bazel).

How so? Bazel produces the same results for the same inputs.

jchw

Bazel doesn't guarantee bit-exact outputs, but also Bazel doesn't guarantee pure builds. It does have a sandbox that prevents some impurities, but for example it doesn't prevent things from going out to the network, or even accessing files from anywhere in the filesystem, if you use absolute paths. (Although, on Linux at least, Bazel does prevent you from modifying files outside of the sandbox directory.)

The Nix sandbox does completely obscure the host filesystem and limit network access to processes that can produce a bit-exact output only.

(Bazel also obviously uses the system compilers and headers. Nix does not.)

dijit

Uh, Either my understanding of Bazel is wrong, or everything you wrote is wrong.

Bazel absolutely prevents network access and filesystem access (reads) from builds. (only permitting explicit network includes from the WORKSPACE file, and access to files explicitly depended on in the BUILD files).

Maybe you can write some “rules_” for languages that violate this, but it is designed purposely to be hermetic and bit-perfect reproducible.

EDIT:

From the FAQ[0]:

> Will Bazel make my builds reproducible automatically?

> For Java and C++ binaries, yes, assuming you do not change the toolchain.

The issues with Docker's style of "reproducible" (meaning.. consistent environment; are also outlined in the same FAQ[1]

> Doesn’t Docker solve the reproducibility problems?

> Docker does not address reproducibility with regard to changes in the source code. Running Make with an imperfectly written Makefile inside a Docker container can still yield unpredictable results.

[0]: https://bazel.build/about/faq#will_bazel_make_my_builds_repr...

[1]: https://bazel.build/about/faq#doesn’t_docker_solve_the_repro...

colordrops

I'm curious, why couldn't packages that are fully reproduceable be marked with metadata, and in your config you set a flag to only allow reproduceable packages? Similar to the nonfree tag.

Then you'd have a 100% reproduceable OS if you have the flag set (assuming that required base packages are reproduceable)

jchw

You could definitely do that, I think the main thing stopping anyone is simply lack of demand for that specific feature. That, and also it might be hard to keep track of what things are properly reproducible; you can kind of only ever prove for sure that a package is not reproducible. It could be non-deterministic but only produce differences on different CPUs or an infinitesimally small percentage of times. Actually being able to assure determinism would be pretty amazing although I don't know how that could be achieved.

colordrops

I assume it would be somewhat of a judgement call. I mean that is the case with nonfree packages as well - licenses and whatnot have to be evaluated. I assume that there are no cases of non-trivially large software packages in the wild that have been formally proven to be reproducible, but I could be wrong.

IHLayman

How this article discusses reproducibility in NixOS and declines to even mention the intensional model or efforts to implement it are surprising to me, since it appears they have done a lot of research into the matter.

If you don’t know, the intensional model is an alternative way to structure the NixOS store so that components are content-addressable (store hash is based on the targets) as opposed to being addressed based on the build instructions and dependencies. IIUC, the entire purpose of the intensional model is to make Nix stores shareable so that you could just depend on Cachix and such without the worry of a supply-chain attack. This approach was an entire chapter in the Nix thesis paper (chapter 6) and has been worked on recently (see https://github.com/NixOS/rfcs/pull/62 and https://github.com/NixOS/rfcs/pull/17 for current progress).

CamouflagedKiwi

> Our most important finding is that the reproducibility rate in nixpkgs has increased steadily from 69% in 2017 to about 91% in April 2023. The high reproducibility rate in our most recent revision is quite impressive, given both the size of the package set and the absence of systematic monitoring in nixpkgs.

That's one way to read the statistic. Another way you could read the graph is that they still have about the same number (~5k) of non-reproducible builds, which has been pretty constant over the time period. Adding a bunch of easily reproducible additional builds maybe doesn't make me believe it's solving the original issues.

> We knew that it was possible to achieve very good reproducibility rate in smaller package sets like Debian, but this shows that achieving very high bitwise reproducibility is possible at scale, something that was believed impossible by practitioners.

Maybe I miss some nuance here, but why is Debian written off as being so much smaller scale? The top end of the graph here suggests a bit over 70k packages, Debian apparently also currently has 74k packages available (https://www.debian.org/doc/manuals/debian-reference/ch02.en....); I guess there's maybe a bit of time lag here but I'm not sure that is enough to claim Debian is somehow not "at scale".

vlovich123

According to https://tests.reproducible-builds.org/debian/reproducible.ht... (which is what the article links to btw) there are ~37k packages tracked for reproducible builds which is ~2.7x smaller than Nix's 100k packages.

dartos

Are they mostly the same 5k packages as 2017?

That seems to be the crux of it.

rssoconnor

I'll repeat my comment from last time this came up.[0]

I could be wrong (and I probably am) but I feel like the term "reproducible build" has shifted/solidified since 2006 when Dolstra's thesis was first written (which itself doesn't really use that term all that much). As evidence the first wikipedia page on "Reproducible builds" seems to have appeared in 2016, a decade after Dolstra's thesis, and even that stub from 2016 appears to prefer to use the term "Deterministic compilation".

Anyhow, when the Nix project originally spoke about "reproducible builds", what I understood was meant by that term was "being able to repeat the same build steps with the same inputs". Because of the lack of determinstic compilation, this doesn't always yield bit-by-bit identical outputs, but are simply presumed to be "functionally identical". There is, of course, no reason to believe that they will necessarily be functionally identical, but it is what developers take for granted every day, and if otherwise would be considered a bug somewhere in the package.

With Nix, when some software "doesn't work for me, but works for you", we can indeed recursively compare the nix derivation files locating and eliminating potential differences, a debugging process I have used on occasion.

I agree that "reproducible builds" now means something different, but that isn't exactly the fault of Nix advocates. I guess a new term for "being able to repeat the same build steps with the same inputs" is needed.

[0]https://news.ycombinator.com/item?id=41953155

jonhohle

I work on a matching decomp project that has tooling to recompile C into binaries matching a 28 year old game.

In the final binaries created by compiled with gcc 2.6.3 and assembled with a custom assembler there appear to be unused, uninitialized data that is whatever was in RAM when whoever compiled the game created the release build.

Since the goal is a matching (reproducible) binary, we have tools to restore that random data at specific offsets. Fortunately our targets are fixed

fngjdflmdflg

What even causes this to happen? ie. what dev tool would add random data from RAM to a binary? Is this likely a bug or is there some reason for it like needing to reach a specific file size somewhere?

aidenn0

Simply calling write() on a C struct can do that, if there is any padding in the struct. Then, of course, there are bugs.

dezgeg

By accidentally writing out uninitialized memory contents to the file with the game still working. It's even worse in DOS era where there is no memory protection so uninitialized memory can contain data used by other processes, so for example parts of source code can get leaked that way. There's a big list of those in https://tcrf.net/Category:Games_with_uncompiled_source_code

tuananh

please do write more about it.

opan

Although I'm aware many distros care somewhat about reproducible builds these days, I tend to associate it primarily with Guix System, I never really considered it a feature of NixOS, having used both (though spent much more time on Guix System now).

For the record, even in the land of Guix I semi-regularly see reports on the bug-guix mailing list that some package isn't reproducible. It seems to get treated as a bug and fixed then. With that in mind, and personally considering Guix kind of the flagship of these efforts, it doesn't surprise me if anyone else doesn't have perfectly reproducible builds yet either. Especially Nix with the huge number of things in nixpkgs. It's probably easier for stuff to fall through the cracks with that many packages to manage.

advisedwang

Is anyone actually implementing the concept of checking hashes with trusted builders? This is all wasted effort if that isn't needed.

I've seen it pointed out (by mjg59, perhaps?) that if you have a trusted builder, why don't you just use their build? That seems to be the actual model in practice.

Reproducibility seems only to be useful if you have a pool of mostly trustworthy builders and somehow want to build a consensus out of that. Which I suppose is useful for a distributed community but does seem like a stretch for the amount of work going in to reproducible builds.

arccy

The superior distro Arch Linux does it: https://reproducible.archlinux.org/

maintainers build the packages, other people check: https://wiki.archlinux.org/title/Rebuilderd#Package_rebuilde...

c0balt

> is anyone actually implementing [..]

Not for NixOS as far as I can tell. You only have this for source derivations where a hash is (usually in a PR) submitted and must be reproducable in CI. This specific example however has the problem that linkrot can be hard to detect unless you regularly check upstream sources.

mhh__

I guess this is a tangent, but Nix to me feels like the right idea with the wrong abstraction. I can't explain / it would take a serious bit of genius to come up with an alternative worth switching to.

Has anyone done any better?

zanecodes

I agree, I feel like Nix is kind of a hack to work around the fact that many build systems (especially for C and C++) aren't pure by default, so it tries to wrap them in a sandboxed environment that eliminates as many opportunities for impurity as it reasonably can.

It's not solving the underlying problem: that build systems are often impure and sometimes nondeterministic. It also tries to solve a bunch of adjacent problems, like providing a common interface for building many different types of package, providing a common configuration language for builds as well as system services and user applications in the case of NixOS and home-manager, and providing end-user CLI tools to manage the packages built with it. It's trying to be a build wrapper, a package manager, a package repository, a configuration language, and more.

Ericson2314

You can use the low level stuff without the language to forge your own journey.

https://github.com/NixOS/nix/blob/master/doc/manual/source/s...

I am working on the docs for this as we speak.

tuananh

so looks like reproducibility rate of nixos is not that high, roughly similar with debian?

https://wiki.debian.org/ReproducibleBuilds

0x457

IIRC any package that uses Java isn't reproducible because system time and fixing it to epoch permamently causes issues in some application builds.

* there're maven and gradle plugins to make builds reproducible.

yjftsjthsd-h

Can you force it to some time other than 0? Ex. I've seen some packages force timestamps to the git commit timestamp, which is nice but still fixed.

Cyph0n

This is an approach you can use when building Docker images in Nix flakes: https://github.com/aksiksi/ncdmv/blob/aa108a1c1e2c14a13dfbc0...

throitallaway

IME Erlang was like this ~8 years ago (the last time I touched it) but things may have changed since then.

arjvik

What issues? I'm not aware of any Java build process that checks timestamps.

paulddraper

JARs are archives, and archives have timestamps.

You can remove those with some extra work.

layer8

Can you elaborate on the root causes?

jf

Aside from this being a great article with lots of interesting details, it's also a rare example of a headline that does NOT follow "Betteridge's law of headlines"

Ericson2314

I got scared and then I was unexpected releaved!

(-- A Nix maintainer)