Verification scope: the nixpkgs
nixos-unstablemodules and upstream documentation consulted in October 2026. Group lists, package counts, and service defaults change with the revision; deployments should use the nixpkgs and Home Manager sources pinned by the project as the authority. No build, activation, or desktop runtime tests were performed for this article.
Why use it?#
NixOS follows the idea of "one flake describing the whole system." Sometimes, though, you want multiple variants: kmscon + Hyprland/niri by default, with a full GNOME desktop available occasionally. Adding GNOME directly would intrude on the main configuration by changing the display manager and adding a large set of packages. Specialisation lets you derive multiple independent system configurations within one flake, each with its own boot entry.
Uses
- Coexisting desktop environments (for example, a TTY in the base configuration and GDM in the gnome variant)
- Isolating experimental configurations, such as a different kernel or kernel parameters
- Keeping the default system as a recovery option; user data, disks, and some runtime state are still shared
How it works: more than copying a configuration file#
How Specialisation is built (nixpkgs source: activation/specialisation.nix):
- Each
specialisation.<name>usesextendModulesto create an independent child configuration by extending the parent configuration's module graph. This is a native feature of the module system, not a copy of the configuration. inheritParentConfig = true(the default) → the child inherits the entire main system, with itsconfigurationblock layered on top- Each variant produces a complete, independent toplevel, with its own systemd units, activation script, and /etc
- The parent toplevel references them through symlinks at
$out/specialisation/<name> - The bootloader discovers them through bootspec (RFC 0125) and creates boot entries
A variant therefore has an independent system toplevel, but it is not a VM or container and does not isolate user data. The Nix store shares identical dependencies; the actual costs are the additional closure references, differing packages, and build work.
Configuration#
# 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
};
}Inheritance and overrides: mkForce / mkDefault
- A variant inherits the main configuration, which may include kmscon, other compositors, input methods, and Home Manager declarations, depending on the parent
- To override options assigned directly in the main configuration (
enable = true), a variant must uselib.mkForce. A different value at the same priority usually produces a conflicting definitions error; mergeable types such as lists instead follow their merge rules. - To make a value in the main configuration overridable by child variants, use
lib.mkDefaultin the main configuration to lower its priority
Nested specialisations are disabled A variant cannot contain further variants: no-clone.nix forces them to be empty. As a result,
/run/current-system/specialisation/is empty in the gnome variant. Usenixos-rebuild switchto return to the base system; you cannot use the same script from inside gnome to switch back.
Switching#
# 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 # 临时激活,不更新启动默认When returning to the base system, explicitly select the original parent flake, for example sudo nixos-rebuild switch --flake .#workstation, without --specialisation. Before building, you can record the parent system's store path and run its bin/switch-to-configuration test as part of your recovery plan; do not rely on a symlink to the parent path being present in the current variant.
Validation: build a variant without switching to it#
# config.system.build.toplevel.specialisation.<name> 不存在,用这个路径:
nix build .#nixosConfigurations.workstation.config.specialisation.gnome.configuration.system.build.toplevelPitfall: new files need git add Git flakes normally include only tracked files; untracked new
.nixfiles are filtered out. Add them to tracking as part of an appropriate Git workflow, or usepath:.#...to explicitly include the current directory.git addis not a commit, and successful evaluation does not prove that a variant can boot.
Related#
- Declarative GNOME Management — the actual contents of the variant
- The Declarative and Runtime Layers of NixOS — variants as "polymorphism" in the declarative layer
Operational boundaries before switching#
Changing display managers, desktop services, or kernels can affect the current graphical session. Save your work, keep a usable TTY/console and a known-bootable base generation available, and expect kernel, boot-parameter, or driver changes to require a reboot in many cases. nix build validates only the artifacts; it does not test GDM login, screen locking, input methods, or user services. These need actual session checks on the target machine.
References & further reading
Adapted from technical notes. Examples use generic names.