Using fixed output paths for a derivation

When should a fixed output path be used for a derivation in nix?

Nix pill #18 says the following:

Finally, the other most used kind of path is when we know beforehand an integrity hash of a file. This is usual for tarballs.

The builder must create the out path and make sure its hash is the same as the one declared with outputHash .

The Nix manual documents the options used to specify the output hash.

I think it could be further explained what does it mean to know beforehand an integrity hash of a file. It would help newcomers (and others) to better understand this concept.

In particular, is it right to say that a derivation with run time dependencies (using for instance buildInputs and propagatedUserEnvPkgs) should not have a fixed output path, because it will change when any dependence change?

One thing you might be misunderstanding: Not just what you normally consider ‘packages’ are derivations. Source code fetchs, NixOS system, your user environment… anything that Nix builds, is a derivation.

The #1 reason we use fixed-output derivations is for network downloads. Since we cannot control the network, we disable it during builds to help with reproducibility.

But what if we do need to download something? We make a compromise: if you’re a fixed-output derivation we enable network access for you, but in return tell me in advance the hash of what you’re going to download and give back as output. This way we retain reproducibility.

For ‘normal’ builds, fixed-output aren’t really designed for them. Being able to provide bit-by-bit identical builds is the ultimate ‘reproducible build’ and is very much an unsolved problem for now, even with Nix.

1 Like

I understand that.

Look at the issue ant-theme: hash missmatch in FOD which reports a failure in building ant-theme due to a hash mismatch. The nix expression uses a fixed-output path:

Can this derivation be a fixed-output one?

Is it right to say that it shouldn’t do that because it depends on some packages through propagatedUserEnvPkgs?

I agree that it shouldn’t be fixed-output, for all the reasons you’ve mentioned.

The original author probably wanted to use the #2 reason we use fixed-output derivations: to save build time. For example, fonts come in zips with individual font files in it, and we need to put them into the correct location for it to become a font package. But this package is not going to change unless we upgrade the font, so to avoid rebuilding this (possibly massive, for stuff like CJK fonts) package we make it fixed-output so it’s considered static even when its build dependencies change.

Unfortunately, for ant-theme it seems that ‘this package is not going to change’ broke, and it’s probably propagatedUserEnvPkgs that’s causing it, but I didn’t verify.

References to derivations in buildInputs are expected to end up in the output so when their hash changes, the hash of all their dependents changes as well. Sometimes buildInputs are used incorrectly instead of nativeBuildInputs for referencing a build-time tool – for example, if the build phase used gnuawk to deterministically replace something. Then depending on other inputs is acceptable in fixed-output derivation but that is rare since it requires the tool to be deterministic.

propagatedUserEnvPkgs can never be used with fixed-output derivations since the derivations listed in it will be written to $out/nix-support/propagated-user-env-pkgs , changing hash of the output whenever hash of one of the pkgs changes.

And/or (as far as I understand) when the output path is self-referential, so the out path cannot contain references to any path within out. Since fixed-output derivations use the hash of the contents (is content-addressable), it would not be possible to compute the hash in such cases.

An example of this is the MKL derivation. It has no dependencies and used to be a fixed-output derivation on Linux x86_64. However, later the derivation was modified to install pkg-config files. Since the .pc are installed to out and contain paths into out, it could not be a fixed-output derivation anymore.

(Of course, there are workarounds for such scenarios, by installing the .pc files in a separate derivation which depends on the fixed-output derivation.)