Partitioning and Bootloaders¶
Overview¶
NixOS does not partition disks at activation time by default. You declare where the system mounts storage—root, swap, EFI System Partition (ESP), and optional encrypted volumes—via fileSystems and swapDevices. Boot loaders are configured separately under boot.loader.*. Both usually live in hardware-configuration.nix (generated by nixos-generate-config during install) and are imported from configuration.nix. On UEFI, align ESP mount paths with boot.loader.efi.efiSysMountPoint, plan ESP size for retained generations (or UKIs), and rebuild after pruning old profiles so loader entries on /boot stay in sync.
Details¶
Disk layout in config. Each mount is an entry in fileSystems, keyed by mount point (for example fileSystems."/"). Each entry needs at least a device (block device path, UUID, or label) and usually fsType. Entries become /etc/fstab lines and corresponding systemd .mount units. Swap is listed in swapDevices. Prefer UUID or label (/dev/disk/by-uuid/…, /dev/disk/by-label/…) over raw /dev/sdX names—they stay stable when drive order changes. You can often omit fsType for ordinary mounts, but specify it for filesystems needed in the initrd that are not ext2/3/4 so the right module is available early. A failed mount aborts startup unless you add options = [ "nofail" ];.
ESP and /boot. On UEFI, both systemd-boot and GRUB expect the EFI System Partition at /boot by default (boot.loader.efi.efiSysMountPoint defaults to /boot). If the ESP is mounted elsewhere (for example /boot/efi or /efi), set boot.loader.efi.efiSysMountPoint to that path and keep fileSystems in sync—or remount on /boot before running nixos-generate-config. Mismatch is a common source of install and upgrade pain. Manual partitioning steps: Manual install.
XBOOTLDR (optional). systemd-boot can store boot-loader entries and kernels on a separate XBOOTLDR partition instead of the ESP. Set boot.loader.systemd-boot.xbootldrMountPoint to where that partition is mounted; the option docs recommend ESP at /efi and XBOOTLDR at /boot per the Boot Loader Specification. When XBOOTLDR is used, $BOOT for entries moves off the ESP—useful when the ESP is small but you still want many generations on a larger /boot partition.
ESP size and generations. The installation manual historically reserves about 512 MiB for the ESP. That is often enough for a fresh system, but each generation copies kernel and initrd onto /boot (or XBOOTLDR). Large kernels, many retained profiles, or per-generation Unified Kernel Images (UKIs; see below) fill the partition quickly. Mitigations: size the ESP (or XBOOTLDR) generously, cap visible generations with boot.loader.systemd-boot.configurationLimit (null keeps every non-GC’d generation), and garbage-collect old system profiles. After deleting generations, run nixos-rebuild boot or nixos-rebuild switch so stale loader entries and files on /boot are pruned—not just nix-store --gc. Symptom guide: Troubleshooting — /boot full.
Boot loaders. Two common choices:
| Boot loader | Typical firmware | Main option |
|---|---|---|
| systemd-boot | UEFI | boot.loader.systemd-boot.enable = true |
| GRUB | BIOS or UEFI | boot.loader.grub.enable = true |
On UEFI, the NixOS manual recommends systemd-boot: it reads kernel and initrd from /boot (or XBOOTLDR) and registers one entry per generation. nixos-generate-config often enables it when the installer is booted in UEFI mode. Related knobs live under boot.loader.efi and boot.loader.systemd-boot (for example boot.loader.efi.canTouchEfiVariables).
GRUB remains common on BIOS and when you need features systemd-boot lacks. BIOS GRUB requires boot.loader.grub.device set to the whole disk (for example "/dev/sda"), not a partition. UEFI GRUB typically uses boot.loader.grub.efiSupport = true and boot.loader.grub.device = "nodev" (ESP holds the EFI binaries). Optional boot.loader.grub.useOSProber can add other OSes to the menu (Windows detection is the usual case). Dual-boot layout notes: Dual boot and VMs.
Custom / external loaders. boot.loader.external disables the built-in GRUB and systemd-boot installers and runs your own installHook against the system toplevel—useful for wrapping third-party or image-specific boot logic without forking nixpkgs loader modules.
Unified Kernel Images (UKI). NixOS exposes boot.uki and builds system.build.uki with systemd ukify, bundling kernel, initrd, kernel command line, stub, and related metadata into one .efi per evaluation. Defaults under boot.uki.settings.UKI pull from the active kernel package, initrd, and boot.kernelParams; you can override via boot.uki.settings or a custom boot.uki.configFile. Options include boot.uki.name, boot.uki.version, and optional boot.uki.tries for boot counting. Each UKI is much larger than separate kernel+initrd files, so retaining many UKI generations on the ESP adds pressure alongside configurationLimit concerns. Wiring UKIs into firmware boot menus and UEFI Secure Boot signing is not handled by default systemd-boot/GRUB paths; that is separate operator work—see Secure Boot and Lanzaboote.
LUKS. Encrypted volumes appear as /dev/mapper/<name> after opening. Point fileSystems."/".device (and other mounts) at the mapper device. Ensure unlock at boot with boot.initrd.luks.devices.<name>.device pointing at the underlying LUKS partition (UUID preferred). nixos-generate-config often detects existing LUKS layouts and pre-fills these entries—verify them. If GRUB must read /boot from an encrypted partition, set boot.loader.grub.enableCryptodisk = true.
Declarative partitioning (disko). disko is a community tool for describing partition tables and filesystems in Nix and applying them before or during install. It complements—not replaces—fileSystems and boot.loader.* in the NixOS config; see the disko page for scope and upstream docs.
Boundaries (what this page is not)¶
- disko internals—declarative partition tables and format modes.
- ZFS and Btrfs pool layout, snapshots, and native encryption.
- Secure Boot and measured boot—signed ESP layout and TPM PCR policy.
Examples¶
Illustrative UEFI layout: root on a btrfs partition by UUID, ESP at /boot, systemd-boot enabled.
{ config, ... }:
{
fileSystems."/" = {
device = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000001";
fsType = "btrfs";
options = [ "subvol=@" ];
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000002";
fsType = "vfat";
};
swapDevices = [
{ device = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000003"; }
];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
}
Cap boot-menu generations when /boot is tight (example value from option docs):
Optional XBOOTLDR split: small ESP at /efi, entries and kernels on /boot:
{
fileSystems."/efi" = {
device = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000010";
fsType = "vfat";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000011";
fsType = "ext4";
};
boot.loader.efi.efiSysMountPoint = "/efi";
boot.loader.systemd-boot.xbootldrMountPoint = "/boot";
boot.loader.systemd-boot.enable = true;
}
LUKS root (shape from the NixOS manual—replace UUIDs and the mapper name):
{
boot.initrd.luks.devices.crypted.device =
"/dev/disk/by-uuid/00000000-0000-0000-0000-000000000004";
fileSystems."/".device = "/dev/mapper/crypted";
}
UEFI GRUB (when not using systemd-boot):
{
boot.loader.grub.enable = true;
boot.loader.grub.device = "nodev";
boot.loader.grub.efiSupport = true;
}
UKI output is available as config.system.build.uki; defaults usually suffice. Override naming or ukify inputs when building images or custom install hooks:
{
boot.uki.name = "nixos";
# boot.uki.settings.UKI.Cmdline = "…"; # optional; defaults include init= and boot.kernelParams
}
References¶
- NixOS manual — File Systems —
fileSystems, labels/UUIDs,nofail - NixOS manual — LUKS-Encrypted File Systems —
boot.initrd.luks.devices, mapper devices - NixOS manual — Installing (UEFI / BIOS boot loader) — systemd-boot vs GRUB; ESP sizing (~512 MiB in examples)
- NixOS options search —
boot.loader - NixOS options search —
boot.uki - disko (GitHub) — declarative partitioning (community)