Flake hard-coded fields and their rationale

I’m hoping someone can explain the rationale for some design decisions around flakes, in particular why certain parts of a flake are effectively hard-coded due to the behaviour of the existing tooling.

The main example in my head is that packages.<system>.x must be a derivation. I’d been playing around with the idea of having a flake support selecting different versions of a package (something like “nix build #somePackage.v11.0.2”). While I could get the actual building of it to work, it comes at the cost of discoverablility, because, for example, nix flake info barfs as soon as it sees packages.<system>.x is an attrset instead of a derivation.

I’ve been mulling over whether the schema of flake outputs needs to be this tight (could the search behaviour for info be overrideable within the flake itself, for instance). I don’t have a hard proposal or anything at this point, but any insights anyone is willing to share on the topic would be appreciated.


I think most of the rationale behind flake design is ultimately documented in the RFC that originates it all: [RFC 0049] Flakes by edolstra · Pull Request #49 · NixOS/rfcs · GitHub

The rationale is effectively that large flakes are expected, and if you need to evaluate a large tree of potentially nested objects, the operation becomes really expensive. You then end up with the problems nix-env -q has.

If you instead limit it to one layer of attributes, you only need to parse attribute names (and not actually evaluate anything), so your nix info and nix search can stay spiffy.

There are probably other ways to avoid this too, but this is the approach that was taken. Flakes are still not finalized, and this is one of the major painpoints, so it may or may not change. Realistically, I doubt it will, the other painpoints will be resolved with flakes depending on other flakes.

To achieve your goal, the de-facto idiomatic solution is to just have multiple packages that override one at the same level and name them e.g. somePackage_latest and somePackage_11_0_2. If you look around nixpkgs, that’s anyway how this has been done even since before flakes (e.g. for the linux kernel, python, java, …).