Hi guys
Today I thought a bit about flake versioning and depending on flakes with a specific version, or version range. I’m not very happy that the current situation seems to be to just use FlakeHub.
I think Nix could solve this quite easily by itself, even without breaking flakes how they currently work.
I don’t have a very deep understanding how Nix handles Flakes and I surely haven’t thought of every edge case. So instead of proposing a finished solution, I just want to dump my head here to see if I can inspire someone with it.
Here’s my idea:
Versioned Flakes
In addition to normal flakes, there could now be a new versioned flake type. Versioned flakes would have everything a normal flake has + a new file at the top of the repository called flake-versions.json
. The content of such a file could be like this:
{
"1.0.0":"6d5fea164f44d58d55453242bed17a867e76aa8a",
"1.0.1":"6f7d3bb008e714168777291d49d4f42faab0e37b",
"2.1.7":"641e0cf442a9284cedf507b42ee08012b400b652",
// and so on
}
This is basically a list of self-references, that tells nix at which commit to find which version of the flake.
Referencing versioned flakes
Now let’s assume we have a versioned flake called “superlib” and flakes A,B,C and D, that depend on each other and also on superlib
A:
superlib
B:
superlib
C:
superlib
D:
superlib
By default, we would get 4 versions of superlib. The only way to get around this is to set “follows” everywhere. But that’s a bad idea, because we don’t even know with what versions of a dependency a flake can deal with and what versions wont work.
As an alternative we could allow setting the version of a dependency like this:
{
inputs.superlib = {
url = "github:VanCoding/superlib";
version = "1.0.1"; # could also be ">1" or other range expressions, like NPM has
};
}
Whenever the version is set like this, Nix would know that the flake has to be a versioned flake. If the referenced flake doesn’t have a flake-versions.json
, Nix would complain.
If the version is specified, Nix would completely change how it resolves flakes. For all flakes with the same url, it would download the only one (the latest) version, just like if you had set follows
everywhere. Then it would look at the flake-versions.json
of that version, and look at what versions have beet requested by the whole dependency tree. There it could try to figure out the most efficient set of versions to satisfy all dependents and also add these to the flake.lock
file with their commits from flake-versions.json
.
When resolving the dependency tree, Nix would then give each dependent the version it previously decided on.
So to wrap up:
If 6 flakes in the dependency tree depend on github:VanCoding/superlib
, Nix would look at the latest commit there, read the flake-versions.json
file and then pick the matching commits from there. It would do this instead of downloading 6 different versions of github:VanCoding/superlib
.
But why?
As I said before, i don’t like the proprietary, centralized approach that FlakeHub currently has. It should be possible that a flake can somehow tell the world where to find which version by itself, without any middlemen.
Additionally, this would make the use of flake versioning completely optional. For some flakes, versioning doesn’t really make sense. For others this would be very beneficial. In the way I described, these two approaches can easily coexist and be mixed.
Again, this is just my brain dump. I’d enjoy discussing this with you. My hope is that someone of the nix developer team gets inspired by this and we could see something like this implemented in the future.