OFFSET偏移
← All articlesOFFSET / FIELD NOTESNO. 079

Building GNOME variants with Specialisation

Derive independent system toplevels from the parent module graph, with clear inheritance, override, and recovery paths.

English translation · Code and commands follow the Chinese original.

IN THESE READING PATHSA declarative GNOME desktop on NixOS ↗
About 4 min readStart reading

Verification scope: the nixpkgs nixos-unstable modules 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):

  1. Each specialisation.<name> uses extendModules to 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.
  2. inheritParentConfig = true (the default) → the child inherits the entire main system, with its configuration block layered on top
  3. Each variant produces a complete, independent toplevel, with its own systemd units, activation script, and /etc
  4. The parent toplevel references them through symlinks at $out/specialisation/<name>
  5. 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 use lib.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.mkDefault in 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. Use nixos-rebuild switch to 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.toplevel

Pitfall: new files need git add Git flakes normally include only tracked files; untracked new .nix files are filtered out. Add them to tracking as part of an appropriate Git workflow, or use path:.#... to explicitly include the current directory. git add is not a commit, and successful evaluation does not prove that a variant can boot.

Related#

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

  1. NixOS specialisation module ↗
  2. NixOS bootspec RFC ↗

Adapted from technical notes. Examples use generic names.

Continue along a reading path

A declarative GNOME desktop on NixOS

  1. 01Declarative GNOME desktop management
  2. 02GNOME module options reference
  3. 03Managing GSettings defaults and dconf state
  4. 04From settings diffs to declarations and extensions
  5. 05Building GNOME variants with Specialisation
  6. 06kmscon and uwsm in Wayland sessions
CONTINUE READING / NEXT ARTICLEkmscon and uwsm in Wayland sessions

Investigate the lifecycles of DRM handoff, systemd user sessions, and XDG autostart separately.