It seems like most uses of stateVersion in NixOS fall into the following categories:
-
Module
foohas changed the default value of an option; this shouldn’t affect existing configurations.Practical example: The default value of
virtualisation.oci-containers.backendwas changed fromdockertopodman.Theoretical example:
services.openssh.openFirewallcurrently defaults totrue, unlike most instances ofopenFirewall, for backwards compatibility. If this were to be changed in the future, it would need to be gated bystateVersion, otherwise any existing systems relying on that default would lose SSH access. -
Package
foohas been renamed upstream tobar. It should continue to be available to aspkgs.fooin existing configurations to avoid breakage, but new configurations should start usingpkgs.bar.Practical example:
pkgs.codimd→pkgs.hedgedoc -
Package
foohas changed it’s (database format/storage directory/other state) since a previous version, and we are able to automatically run a migration script ifstateVersionis old enough to be applicable.Practical examples:
services.sourcehut,services.timesyncd -
Package
foocannot be updated automatically. Perhaps it must be incrementally updated to each major version, or may require manual migration steps when upgrading. Unless the user specifics a specific package version, we must continue to install the same version by default for a particularstateVersion. If that version is no longer available in Nixpkgs, we need to throw an error with migration instructions.Practical examples: Nextcloud, postgresql
While [1] and [2] should continue to work fine with an opaque monotonic counter, and may benefit from not being bound to release versions, [3] and [4] seem to rely on release versions as a point of synchronization, and I’m unsure how an
There are positives to this proposal. It would allow for predictable conditions on a stable release, while not tying every stateVersion change to a release. However, it doesn’t address the original motivation of this thread, and it’s unclear how beneficial it would be over the current solution.
While I personally don’t have any interaction with third-party modules, I do agree there is utility in having a release-based stateVersion, as modules (third-party or otherwise) can easily include stateVersion conditionals without needing to coördinate to increment the current default stateVersion.
I don’t think it is accurate to assume we can drop most uses of stateVersion. Even if we no longer offer old versions of packages, or no longer include migrations, we should still throw on an old stateVersion rather than allow things to silently break with no explanation or instructions.
It is also an implementation detail of Nixpkgs, which may have effects on other projects in the Nix ecosystem.
I am not yet convinced that stateVersion being associated with a release version is a bad thing; however, I completely agree that stateVersion being visually identical to a release version is bad and confusing to many users.
If we only wish to make the value opaque to avoid confusion, we could define a new option that takes an encoded value for stateVersion, and stateVersion itself would default to a function that decodes this value.
As a trivial example, suppose on install we set a new option stateCode to a simple character translation (0123456789. → abcdefghijk) of stateVersion.
e.g. system.stateCode = "cekaf"; (“24.05”)
A Nix function would reverse this transposition to set stateVersion at eval, to allow versionBefore and versionAtLeast to continue working as before.