Why does nix-direnv recommend setting nix.settings.keep-outputs?

Hey, I’m wondering why nix-direnv recommends in its readme to set nix.settings.keep-output = true. For the purpose of preventing undesired garbage collection, isn’t it enough that nix-direnv creates link in .direnv?

I’m not at all familiar with nix-direnv, but here’s what I would guess is a pretty good guess.

If you have a derivation for which you would like to prevent all of its build inputs from being GC’d, the easiest way is to set keep-outputs = true. The reason is that a GC root to a a given path is only going to keep its runtime inputs alive, and its “derivation” alive (by default). The derivation will keep the whole build hierarchy logically but not physically. That build hierarchy needs its outputs kept alive to keep those build-time inputs kept alive as well. So keep-outputs says “all those derivations that are kept alive by default… well they should also keep their build outputs so I don’t have to re-acquire them to do my build again”.

The downside is e.g. if you happen to have some distant bootstrap tool in your store (like the GCC that we use to build the real GCC for stdenv), that’s going to be kept needlessly alive because it is in the derivation logical closure, but it’s not at all in the runtime closure of your system (at least, most likely). So you could end up keeping alive tons of excess build tools that only have to do with earlier stage build tools, and you just don’t need such early stage build tools.

My example was bootstrap stuff like super early GCC but that’s only the most extreme category of examples. Nixpkgs has tons of intermediaries that realistically sit in this category of “unneeded but within the build closure”. Personally I find this downside worth it. I just don’t care if there’s some extra 30% greater space taken by the store to satisfy my desire to keep the build time closure alive; but it’s a cost worthy of awareness

1 Like