PAYATHON 2026

如何在 flake.nix 的 inputs 中定义和引用版本变量?

数据小许

不能直接在标准 Nix flakes 的 inputs 中定义一个普通变量,再让两个 URL 引用它。inputs 有静态结构限制。outputs 函数内部可以正常使用 let ... in,但其中的变量不能反过来决定输入依赖。

如果需要让三处共享一个版本值,可以在运行 Nix 之前,用模板生成静态的 flake.nix。对于这样的配置,直接维护两处分支声明通常也不难。

为什么普通 Nix 写法在这里不适用?

示例中的三处 25.11 分别用于两个输入分支和一个模块参数。前两处是依赖声明,第三处是 outputs 内部的普通 Nix 表达式,处理阶段不同。

Nix 需要先读取输入声明、解析依赖并处理锁文件,然后才能将输入传给 outputs。因此,不能用下面这种写法让输入 URL 依赖外部变量:

# 这种写法不能作为标准 flake.nix 使用。
let
  release = "25.11";
in {
  inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-${release}";
  # ...
}

把 let ... in 移到 inputs 内部,或者用 import 读取版本文件,也不能将输入声明变成任意可求值的 Nix 表达式。这是 flakes 对输入和元数据的限制,nix.dev 的说明提到了这一点。

原配置中的:

inputs.nixpkgs.follows = "nixpkgs";

可以继续保留。它使 Home Manager 的 nixpkgs 输入使用顶层的同一个输入,但不会提取版本号,也不会自动改写 Home Manager 的分支名称。follows 引用的是依赖图中的输入路径,详见 Nix flake 输入文档。

方案一:保留静态分支声明

最直接的做法是继续显式声明两个分支:

inputs = {
  nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";

  home-manager = {
    url = "github:nix-community/home-manager/release-25.11";
    inputs.nixpkgs.follows = "nixpkgs";
  };
};

升级时一起修改这两个分支。Home Manager 的稳定分支应与使用的 Nixpkgs 发布分支对应,Home Manager 升级指南采用的也是这种配置方式。

第三处 release 是否应该一起修改,要先看 home.nix 如何使用它。仅凭 extraSpecialArgs 的声明,无法确定它与输入分支版本是否具有相同含义。

方案二:用模板实现版本号只维护一次

如果确认三个位置都表示同一个发布版本,可以增加一个生成步骤。

先将原配置复制为 flake.nix.in,把三处版本值替换成 @RELEASE@。两个输入 URL 变为:

nixpkgs.url = "github:nixos/nixpkgs/nixos-@RELEASE@";

home-manager = {
  url = "github:nix-community/home-manager/release-@RELEASE@";
  inputs.nixpkgs.follows = "nixpkgs";
};

outputs 中的声明变为:

release = "@RELEASE@";

其余配置保持原样。接着,在同一目录创建 generate-flake.py:

from pathlib import Path

release = "25.11"
placeholder = "@RELEASE@"

template = Path("flake.nix.in").read_text(encoding="utf-8")
if template.count(placeholder) != 3:
    raise SystemExit("模板中应包含三处 @RELEASE@,请检查后再生成。")

Path("flake.nix").write_text(
    template.replace(placeholder, release),
    encoding="utf-8",
)

在该目录运行:

python3 generate-flake.py
nix flake update

版本号只需在生成脚本里维护一次。Nix 实际读取的仍然是包含静态 URL 的 flake.nix,输入限制仍然适用。

脚本会覆盖 flake.nix,后续应修改模板,再重新生成。模板、生成脚本、生成后的 flake.nix 和 flake.lock 应保持同步。生成步骤只负责替换文本,不会验证对应分支是否存在,也不会证明配置能够成功构建。

注意:不要把 home.stateVersion 自动绑定到输入版本

原问题没有提供 home.nix。如果传入的 release 最终用于:

home.stateVersion = release;

就不适合把三处版本号统一为一个会随升级变化的值。

home.stateVersion 控制与持久状态相关的兼容默认值,升级 Nixpkgs 或 Home Manager 时通常应保持原值。只有阅读相关发布说明并完成必要迁移后,才考虑调整它。具体说明见 Home Manager 的状态版本说明。

如果 release 只是供模块使用的当前发布版本标签,可以用模板统一维护;如果它承担的是 home.stateVersion 的作用,就应单独保留。

备注:内容仅供参考。