核验范围:2026 年 10 月查询的 nixpkgs
nixos-unstable模块与上游文档。分组列表、包数和服务默认值会随 revision 改变;部署时应以项目锁定的 nixpkgs 和 Home Manager 源码为准。本文没有构建、激活或桌面运行测试。
为什么需要#
NixOS 的配置是"一份 flake 描述整个系统"。但有时你想要多个形态:默认走 kmscon + Hyprland/niri,偶尔想要完整 GNOME 桌面。直接加 GNOME 会污染主配置(换登录管理器、塞一堆包)。Specialisation 允许你在一个 flake 里派生多个独立系统配置,各自有自己的 boot 条目。
用途
- 多桌面环境共存(示例:base 使用 TTY,gnome 变体使用 GDM)
- 实验性配置隔离(换内核、换内核参数)
- 可保留默认系统作为恢复入口;用户数据、磁盘与部分运行状态仍共享
机制:它不是一个配置文件复制#
Specialisation 的构筑本质(nixpkgs 源码 activation/specialisation.nix):
- 每个
specialisation.<name>用extendModules在父配置的模块图上扩展出一个独立子配置(不是复制配置,是模块系统的原生能力) inheritParentConfig = true(默认)→ 子配置继承整个主系统,configuration块叠加其上- 每个变体生成一个完整独立的 toplevel(自己的 systemd 单元、activation 脚本、/etc)
- 父 toplevel 里 symlink 引用它们:
$out/specialisation/<name> - bootloader 通过 bootspec(RFC 0125)发现并生成 boot 条目
所以变体有独立的系统 toplevel,但不是 VM、容器或独立用户数据隔离。Nix store 会共享相同的依赖;增加的 closure 引用、差异包和构建工作才是实际成本。
配置#
# host/gnome.nix(被 host/default.nix import)
{ config, lib, pkgs, ... }:
{
specialisation.gnome.configuration = {
services.desktopManager.gnome.enable = true;
services.displayManager.gdm.enable = true;
services.kmscon.enable = lib.mkForce false; # ← 见下方 mkForce
};
}继承与覆盖:mkForce / mkDefault
- 变体继承主配置(例如 kmscon、其他 compositor、输入法和 Home Manager 声明,依父配置而定)
- 主配置里硬赋值(
enable = true)的选项,变体要覆盖必须lib.mkForce,与父配置值不同且优先级相同,通常会报 conflicting definitions;列表等可合并类型则依其合并规则处理 - 如果想让主配置的值允许被子变体覆盖,主配置里写
lib.mkDefault(降低优先级)
嵌套 specialisation 被禁用 变体内部不能再有变体(no-clone.nix 强制清空)。所以在 gnome 变体里
/run/current-system/specialisation/是空的——切回 base 用nixos-rebuild switch,不能在 gnome 里用同样的脚本切回。
切换#
# 1. 重启,boot 菜单选 "NixOS (gnome)"(条目名 = specialisation 的 key)
# 2. 运行时切换(不重启,激活当前 generation 的变体)
sudo nixos-rebuild switch --specialisation gnome
# 3. 直接用已构建变体的激活脚本
sudo /run/current-system/specialisation/gnome/bin/switch-to-configuration switch # 激活并更新启动配置;具体启动项由 bootloader 决定
sudo /run/current-system/specialisation/gnome/bin/switch-to-configuration test # 临时激活,不更新启动默认回 base 时明确选择原始父 flake,例如 sudo nixos-rebuild switch --flake .#workstation(不带 --specialisation)。构建前可记录父系统 store 路径,按恢复计划运行其 bin/switch-to-configuration test;不要依赖当前变体下存在父路径 symlink。
验证(不切换就构建变体)#
# config.system.build.toplevel.specialisation.<name> 不存在,用这个路径:
nix build .#nixosConfigurations.workstation.config.specialisation.gnome.configuration.system.build.toplevel坑:新文件要 git add Git flake 通常只纳入已跟踪文件;新
.nix文件未跟踪会被过滤。可在适当的 Git 流程中加入跟踪,也可使用path:.#...明确纳入当前目录。git add不等于提交,评估成功也不等于变体可启动。
关联#
- GNOME 声明式管理 — 变体的实际内容
- NixOS 声明层与运行时层 — 变体 = 声明层的"多态"
切换前的运行边界#
切换显示管理器、桌面服务或内核可能影响当前图形会话。保存工作、保留可用 TTY/控制台与已知可启动的 base generation;内核、启动参数或驱动变化往往需要重新启动。nix build 只验证产物,不验证 GDM 登录、锁屏、输入法和用户服务,需要目标机器的实际会话检查。
参考与延伸
根据技术笔记重新整理,示例使用通用名称。