Nix Flakes is an experiment that did too much at once…
… and it sucks because so much of it is good, or are good undercooked ideas.
This post is not about the implementation details. I'm not judging if the features are good or bad. This post is about the process in which it came to be within the Nix codebase.
First, let's list what I see the Flakes flurry of features as:
- Dependency locking/tracking between Nix expressions (
- Fetching dependencies with a common interface (
- Harmonized declarative interface
- New CLI interface semantics
- Pure evaluation semantics (not exactly, but currently linked to the Flakes mental model)
Hopefully I didn't forget anything important here.
That's a lot of stuff! None of them trivial.
It is my opinion that doing all that at once led to those issues:
- None of these features are done1, none are ready to use, even though it's been a while.
- There is no partial opt-in for most features, they must all be used at once.
- No place for third-party innovation on all these fronts (dead on arrival).
I am not writing this authoritatively, I am not involved with the development of Nix itself.
Let's dig in the reality I see. It may hurt.
Is Flakes ready yet?
The way I see it, Flakes is quagmired in a tar pit, waiting for the features to be reviewed, made manageable, and finished.
Anyone pushing for them to "just" be marked "stable" already does not appreciate the heavy meaning behind marking them stable.
Yes, they are routinely used as if their current form is final. Yes, it will cause headaches for users if changes are needed. No, we can't just decide to live with that technical debt.
It is important to let the Nix maintainers team decide on how to handle this situation, as they themselves will handle maintaining it. Deciding to mark them "stable" today is pushing a large load on their back.
Keeping the door open for breaking changes does not mean the goal is to wreck every user's setup. Instead, it means ensuring that the Nix ecosystem does not have to maintain a possibly flawed system forever. Breaking changes would likely target issues only, and allow for a smooth transition from the flawed initial version. Stabilizing the interface means it's done.
Again, making a breaking change does not mean one day all Flakes setups break. Rather, it ensures that anything bad can be deprecated and removed in a fair amount of time. After all, Nix prides itself in still allowing many years old expressions to evaluate just fine.
With hindsight, I think I was right thinking that Flakes shouldn't have been pushed as much as they were. Doing so before they were ready, means there is de-facto reliance on ossifying features, and makes it hard to change anything that may need to be changed.
This is to the detriment of Nix and Flakes as a whole, whether you think the current feature set is okay or not.
Flakes implement useful things, but too many things at once, and keeps it all to itself.
Saying all is a stretch, but a lot of the features are behind a single feature flag.
There is strong coupling between the features, which must have been helpful for building them, but now hurts the Nix ecosystem.
Using some parts of it (e.g.
builtins.fetchTree) ends-up needlessly locked behind a feature flag.
In turn, it means those features are not exercised outside of the built-for-flake feature set.
I expect features will end-up finding edge cases that were not obvious once made available for all use-cases.
Innovation is blocked
Any new effort that is tangential or concurrent to any of the facets of the monolithic Flakes is dead on arrival.
Attempts at doing any of the things Flakes does will invariably be met with “ why don't you just use Flakes? ”.
That, in itself may or may not be an issue; ignore the haters. But here's the rub: it disincentivises any work toward exploring alternative approaches. Whether you agree or not with alternative approaches, monocultures are bad. Experimenting with ways to do things should be cultivated.
Flakes appeared on the radar around early to mid 2020, added to a stable release in late 2021. In practice it's now been about three years we've lost of potential interesting new ways to think about these problems. And given how rigid they are, only more years to count.
I don't know.
I'm not sure I should know.
There is one thing I can say, though, is that we need to tread carefully and stabilize the features one at a time. Ideally we'd also extricate them from the monolith, and make them useful basic building blocks. We need to let the Nix core team plan the path forward, and leave the time they need.
I do think that ultimatums and deadlines from external forces are counter-productive. If you want it to be done in a timely manner, help the core team get the help and resources they need.
I will not be updating the core of the post, because I don't have edits tracking facilities. As a replacement, I'm adding thoughts precisions or corrections as footnotes.
The vagueness around claims of what is and isn't stable is by design: it doesn't matter for the message. The message is that it’s too much all at once. Flakes is being blocked by itself. ↩