Whilst writing a comment documenting a line of my NixOS configuration I found myself writing up a bit of a rant that I thought I’d share on the forum instead,
From what I understand, Flakes use what is supposedly a subset of Nix’s language, in a way that is meant to restrict their complexity for the purpose of enhancing package reliability.
This does not seem beneficial to people who use Flakes for the purpose of managing multiple system configurations with a single codebase. That caveat also gave me a lot of trouble in trying to understand how the Nix language even works! And as it turns out, I’m not the only one confused by it.
Regardless of capability, Flakes share the “.nix” extension with regular Nix files, which is a lack of clarity I consider to be a big UX issue. In my opinion, it should be completely clear what (programming or markup) language should be expected inside of a file based on its extension alone, especially when the syntax of both possible options is practically identical.
Here is my proposal for refining the standards:
Lift complexity restrictions from flake.nix files (make them use the regular Nix language).
Introduce a new standard for Flake files, with a new format (something like: flake.nixf) that would more clearly indicate it being functionally different from regular “.nix” files.
Make the new format fully compatible with the current syntax and capabilities of flake.nix files, so that all it takes for Flake maintainers to conform to that new standard is a simple file rename.
Update command-line tools to give out warnings about Flakes using the .nix file extension during the migration period.
These changes would aim to lift unnecessary restrictions from Flake-based system configs, provide more clarity on the functional capabilities of a given file, and introduce as little friction as possible.
I’d be very interested to hear some second opinions on the subject. I’m no expert on Nix, so if there is a major problem with my proposal I’m not seeing (aside from it possibly being a large-scale, breaking change), do let me know!
This isn’t quite true, though often stated that way, partially to incite against the concept.
The syntax is definitely nix, but evaluation is prohibited outside the outputs attribute.
The reason for this is that evaluating code takes time, and flake inputs need to be able to be resolved quickly across a potentially deeply nested tree. Allowing evaluation in that context would potentially slow down the ecosystem to a crawl.
But yes, people are indeed confused by this. There are certainly proposals to move the inputs to a different file (flake-inputs.toml?) and such. It’s one of the pain points that are often cited as a reason for disliking flakes.
The restriction on inputs complexity is mostly to wholesale avoid “bootstrapping” or path dependency problems where you have to fetch one thing in order to even know what to fetch next. (Assuming you didn’t create an infinite recursion, which would also be a possibility)
outputs is pretty much normal Nix. nix flake check imposes some rules on it, but that’s technically optional.
I think another goal should be ease and reliability of automated editing, but the current flake.nix/inputs restriction only goes partway to achieve that.
Lossless Nix AST editing isn’t nearly as widely supported as formats like JSON or even JSONC or TOML.
Having only two files might feel nicer than three, but the input specifications should be separate from the lock file for usability reasons, and I don’t think that any of that overrides the automation argument.
Perhaps this could be combined with this other lingering idea that perhaps the outputs could be defined in a simple language like TOML too.
Then the “inputs” file (whatever the name and format would be) could be put in charge of picking a framework or entrypoint that becomes responsible for providing the outputs based on the flake directory and inputs. (e.g. flake-parts or blueprint)
Yeah, I based it on Eelco’s idea (or wish?) to have simpler output definitions, but it converges to something very similar to devenv, which is a great sign!
I really enjoy this idea, it’d go a long way to fixing what I think are major usability issues with flakes; I don’t really think NixOS users should ever touch a flake.nix, as 99% of its contents are pointless in that context, and many flakes end up doing far more than they should just because they have the option to.
Slimming down the format to a kind of template/specification input + dependencies would make flakes way less busy for each individual use case, while maintaining basically all the power, and solve the current hard-coding of output specs nix flake check relies on. Then add easily programmatically editable inputs? Sign me up!
I’m imagining something like:
[inputs]
nixpkgs.url = "https://channels.nixos.org/nixos-25.11/nixexprs.tar.xz"
[entrypoints]
# Hm, needs work; maybe a new attribute on inputs?
list = [ nixpkgs ]
[nixpkgs]
nixosConfiguration = ./configuration.nix
… and that’s a simple flake from someone who knows what they’re doing. Imagine if the home-manager docs could just tell you to add it to your inputs instead of giving you the poor advice of writing an inline module in flake.nix.