It seems like most uses of stateVersion
in NixOS fall into the following categories:
-
Module
foo
has changed the default value of an option; this shouldn’t affect existing configurations.Practical example: The default value of
virtualisation.oci-containers.backend
was changed fromdocker
topodman
.Theoretical example:
services.openssh.openFirewall
currently 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
foo
has been renamed upstream tobar
. It should continue to be available to aspkgs.foo
in existing configurations to avoid breakage, but new configurations should start usingpkgs.bar
.Practical example:
pkgs.codimd
→pkgs.hedgedoc
-
Package
foo
has changed it’s (database format/storage directory/other state) since a previous version, and we are able to automatically run a migration script ifstateVersion
is old enough to be applicable.Practical examples:
services.sourcehut
,services.timesyncd
-
Package
foo
cannot 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.