-
Notifications
You must be signed in to change notification settings - Fork 0
Specialisations
Boot-time system configurations for different use cases in NullOS.
Specialisations allow you to have multiple NixOS configurations in one system, selectable at boot time via GRUB menu. Common uses:
- GPU switching (integrated vs. dedicated)
- Different kernel versions
- Alternative desktop environments
- Development vs. production modes
NullOS implements GPU switching for hybrid graphics systems:
Base Configuration:
specialisation = lib.mkIf vars.useNvidiaPrime {
nvidia.configuration = {
system.nixos.tags = [ "nvidia" ];
hardware.nvidia = {
prime.offload.enable = lib.mkForce false;
prime.sync.enable = lib.mkForce true;
};
};
};This creates two boot options:
- Default - Intel integrated GPU (power saving)
- nvidia - NVIDIA GPU always active (performance)
When booting, GRUB shows:
NixOS - Default
NixOS - nvidia
NixOS - configuration.nix (previous generation)
Select the specialisation you want to use.
Tags appear in system information:
cat /run/current-system/nixos-version
# Shows: 24.11.20250113.dirty (nvidia)Power saving mode:
hardware.nvidia.prime = {
offload = {
enable = true;
enableOffloadCmd = true;
};
intelBusId = "PCI:0:2:0";
nvidiaBusId = "PCI:1:0:0";
};Features:
- Intel GPU used by default
- NVIDIA GPU powered off when not needed
- Longer battery life
- Explicit GPU selection with
nvidia-offloadcommand
Usage:
# Run specific app on NVIDIA
nvidia-offload glxinfo | grep "OpenGL renderer"
nvidia-offload minecraftPerformance mode:
hardware.nvidia.prime = {
sync.enable = true;
intelBusId = "PCI:0:2:0";
nvidiaBusId = "PCI:1:0:0";
};Features:
- NVIDIA GPU always active
- Maximum performance
- Higher power consumption
- All applications use NVIDIA by default
When to use:
- Gaming sessions
- 3D rendering
- Video editing
- Machine learning
- External displays (if wired directly to dGPU)
In any NixOS configuration file:
{ config, pkgs, lib, ... }:
{
specialisation.name = {
configuration = {
# Configuration overrides
};
};
}specialisation.latest-kernel = {
configuration = {
system.nixos.tags = [ "latest" ];
boot.kernelPackages = pkgs.linuxPackages_latest;
};
};Creates boot option with latest kernel instead of LTS.
specialisation.gaming = {
configuration = {
system.nixos.tags = [ "gaming" ];
# Performance optimizations
powerManagement.cpuFreqGovernor = "performance";
# Additional packages
environment.systemPackages = with pkgs; [
gamemode
mangohud
];
# Services
programs.gamemode.enable = true;
# Kernel parameters
boot.kernelParams = [
"mitigations=off" # Security vs performance trade-off
];
};
};specialisation.kde = {
configuration = {
system.nixos.tags = [ "kde" ];
# Disable Hyprland
programs.hyprland.enable = lib.mkForce false;
# Enable KDE
services.xserver.enable = true;
services.desktopManager.plasma6.enable = true;
services.displayManager.sddm = {
enable = true;
wayland.enable = true;
};
};
};You can have multiple specialisations:
specialisation = {
nvidia = {
configuration = {
system.nixos.tags = [ "nvidia" ];
# NVIDIA config
};
};
gaming = {
configuration = {
system.nixos.tags = [ "gaming" ];
# Gaming config
};
};
nvidia-gaming = {
configuration = {
system.nixos.tags = [ "nvidia" "gaming" ];
# Combined config
};
};
};This creates boot menu:
- NixOS - Default
- NixOS - nvidia
- NixOS - gaming
- NixOS - nvidia-gaming
Specialisations inherit base configuration, then override:
# Base configuration
services.printing.enable = true;
programs.hyprland.enable = true;
specialisation.minimal = {
configuration = {
# Inherited: printing still enabled
# Override: disable Hyprland
programs.hyprland.enable = lib.mkForce false;
};
};Use lib.mkForce to override existing values.
cat /run/current-system/specialisation
# Shows: nvidia (if in specialisation)
# Empty if defaultSpecialisations can set environment variables:
specialisation.nvidia.configuration = {
environment.variables.SPECIALISATION = "nvidia";
};Then check:
echo $SPECIALISATIONOnly enable on specific machines:
specialisation = lib.mkIf (vars.hostname == "nslapt") {
nvidia = {
configuration = {
# Laptop-specific NVIDIA config
};
};
};Or:
specialisation = lib.mkIf vars.useNvidiaPrime {
nvidia = {
configuration = {
# Only on machines with NVIDIA
};
};
};specialisation.development = {
configuration = {
system.nixos.tags = [ "dev" ];
# Development tools
environment.systemPackages = with pkgs; [
gdb
valgrind
strace
];
# Allow insecure packages for testing
nixpkgs.config.allowInsecure = true;
# Debug kernel
boot.kernelPackages = pkgs.linuxPackages_latest;
boot.kernelParams = [ "debug" ];
};
};specialisation.testing = {
configuration = {
system.nixos.tags = [ "testing" ];
# Test new software
environment.systemPackages = with pkgs; [
experimental-package
];
# Override unstable packages
nixpkgs.config.packageOverrides = pkgs: {
firefox = pkgs.firefox-beta-bin;
};
};
};specialisation.rescue = {
configuration = {
system.nixos.tags = [ "rescue" ];
# Minimal services
systemd.services = lib.mkForce {};
# Shell access
systemd.services.rescue = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.bash}/bin/bash";
};
};
};
};Normal rebuild builds all specialisations:
sudo nixos-rebuild switch --flake .#hostname# Build but don't activate
sudo nixos-rebuild build --flake .#hostname
# Manually activate specialisation
/nix/var/nix/profiles/system/specialisation/nvidia/bin/switch-to-configuration testSet default specialisation:
boot.loader.grub = {
default = "saved"; # Remember last choice
# or
default = 0; # First entry (default)
default = 1; # Second entry (first specialisation)
};boot.loader.timeout = 5; # 5 seconds to chooseboot.loader.grub.configurationLimit = 10; # Keep last 10 generationsEach specialisation is a separate configuration:
# Check sizes
du -sh /nix/var/nix/profiles/system*
# Clean old generations
sudo nix-collect-garbage --delete-older-than 30d
# Keep only specific generations
sudo nix-env --profile /nix/var/nix/profiles/system --delete-generations +5Boot into default configuration:
- Select default in GRUB
- Fix specialisation configuration
- Rebuild
# Switch back to default
sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch# In specialisation, use lib.mkForce
specialisation.nvidia.configuration = {
# This will override base config
hardware.nvidia.prime.offload.enable = lib.mkForce false;
};- Use Tags - Makes specialisation visible in system info
- Test First - Test specialisation before committing
- Document Purpose - Comment why specialisation exists
- Limit Number - Too many = confusing boot menu
- Clean Old Generations - Specialisations multiply disk usage
Not recommended, but possible:
specialisation.a = {
configuration = {
specialisation.b = {
configuration = {
# Nested config
};
};
};
};This creates:
- Default
- a
- a → b
# List specialisations
ls /nix/var/nix/profiles/system/specialisation/
# View configuration
cat /nix/var/nix/profiles/system/specialisation/nvidia/nixos-versionComment out or remove from configuration:
# specialisation.nvidia = {
# configuration = {
# # ...
# };
# };Then rebuild:
sudo nixos-rebuild switch --flake .#hostnameOld specialisations remain in previous generations until garbage collected.
{ config, pkgs, lib, vars, ... }:
{
# Base configuration
programs.hyprland.enable = true;
# GPU specialisation
specialisation = lib.mkIf vars.useNvidiaPrime {
nvidia-performance = {
inheritParentConfig = true;
configuration = {
system.nixos.tags = [ "nvidia" "performance" ];
# Force NVIDIA active
hardware.nvidia.prime = {
offload.enable = lib.mkForce false;
sync.enable = lib.mkForce true;
};
# Performance tuning
powerManagement.cpuFreqGovernor = lib.mkForce "performance";
# Gaming packages
environment.systemPackages = with pkgs; [
gamemode
mangohud
];
programs.gamemode.enable = true;
# Set environment variable
environment.variables.GPU_MODE = "nvidia";
};
};
};
}- NVIDIA - NVIDIA PRIME configuration
- Customization Guide - System customization
- Services - Managing services
- Troubleshooting - Boot issues