NixOS on ARM/Raspberry Pi

Revision as of 17:15, 18 July 2026 by JamieMagee (talk | contribs) (Replace outdated Raspberry Pi guidance with current images, nixos-hardware profiles, the U-Boot/extlinux boot flow, firmware management, and declarative config.txt)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Raspberry Pi boards use Broadcom systems-on-chip and a board-specific boot process. For 64-bit models, the generic AArch64 SD image is the usual starting point. Raspberry Pi firmware starts U-Boot, which reads the extlinux configuration generated by NixOS. The nixos-hardware repository provides profiles for Raspberry Pi 2, 3, 4, and 5. These profiles select Raspberry Pi downstream kernels and support declarative config.txt generation.[1]

Raspberry Pi family
A Raspberry Pi 3 with enclosure.
Manufacturer Raspberry Pi Ltd
Recommended architecture AArch64 on 64-bit boards
Boot method Raspberry Pi firmware and U-Boot

Support

AArch64 has an official NixOS binary cache. ARMv6 and ARMv7 can still be built from Nixpkgs, but NixOS does not publish binary caches for them.[2]

Board family Recommended architecture NixOS image nixos-hardware profile Notes
Raspberry Pi 1, Zero, and Zero W ARMv6 Build from Nixpkgs or use a community image None No official binary cache
Raspberry Pi 2 ARMv7 Build from Nixpkgs or use a community image raspberry-pi-2 No official binary cache. The profile targets 32-bit ARMv7 and enables OpenSSH by default. Later BCM2837-based revisions can run AArch64, but there is no dedicated 64-bit profile.
Raspberry Pi Zero 2 W AArch64 Generic AArch64 SD image None The image contains Zero 2 W boot files, but there is no dedicated board profile.
Raspberry Pi 3 AArch64 Generic AArch64 SD image raspberry-pi-3 ARMv7 is a best-effort alternative.
Raspberry Pi 4, Pi 400, and CM4 AArch64 Generic AArch64 SD image raspberry-pi-4 The profile includes optional modules for several peripherals and HATs.
Raspberry Pi 5, Raspberry Pi 500, Raspberry Pi 500+, and Compute Module 5 AArch64 Generic AArch64 SD image on unstable raspberry-pi-5 NixOS 26.05 images do not include the Pi 5 boot files. Use an image from nixos-unstable.[3]

Peripheral support depends on the selected kernel, device tree, firmware, and board revision.

Installation

Generic AArch64 image

For the Zero 2 W, Pi 3, and Pi 4 families, download a current AArch64 SD image from the ARM installation page. For Pi 5, use a nixos-unstable image containing PR #537862. NixOS 26.05 images do not contain the required boot files.[3] The standard installation path uses an ARM SD image rather than the PC-oriented NixOS ISO. UEFI is a separate advanced setup.

Write the decompressed image to a microSD card as described on the ARM installation page. Check the destination device carefully because writing the image erases it. The SD image contains a mutable NixOS system, so after the first boot you can create a configuration and use nixos-rebuild without running a separate installer.

The stock image uses the generic NixOS kernel. Import a board profile if you need the Raspberry Pi downstream kernel or the board-specific options described below.

Custom SD image

A custom image can combine the Nixpkgs AArch64 image module with a nixos-hardware profile. When a custom image imports both modules, the profile's firmware module replaces the stock firmware population hook. Enable U-Boot explicitly so that the image contains u-boot.bin and the corresponding kernel= entry in config.txt.

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    nixos-hardware = {
      url = "github:NixOS/nixos-hardware/master";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { nixpkgs, nixos-hardware, ... }: {
    nixosConfigurations.rpi4-image = nixpkgs.lib.nixosSystem {
      system = "aarch64-linux";
      modules = [
        "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix"
        nixos-hardware.nixosModules.raspberry-pi-4
        ({ lib, ... }: {
          # The pinned Raspberry Pi kernel does not build the ZFS module.
          boot.supportedFilesystems.zfs = lib.mkForce false;
          hardware.raspberry-pi.firmware.uboot.enable = true;
        })
        ./configuration.nix
      ];
    };
  };
}

Build nixosConfigurations.rpi4-image.config.system.build.sdImage. The ZFS override stops the base NixOS image profile from building an incompatible out-of-tree module. This ext4 image does not use ZFS. A system that requires ZFS must select a kernel supported by the packaged ZFS module.

A board profile does not define a disk layout. Its firmware population step supports cross-compilation, but support in other packages varies.[4]

Board profiles

The flake module names are:

Board Flake module Channel import
Raspberry Pi 2 nixos-hardware.nixosModules.raspberry-pi-2 <nixos-hardware/raspberry-pi/2>
Raspberry Pi 3 nixos-hardware.nixosModules.raspberry-pi-3 <nixos-hardware/raspberry-pi/3>
Raspberry Pi 4 nixos-hardware.nixosModules.raspberry-pi-4 <nixos-hardware/raspberry-pi/4>
Raspberry Pi 5 nixos-hardware.nixosModules.raspberry-pi-5 <nixos-hardware/raspberry-pi/5>

A flake configuration for a Pi 4 can import the profile as follows:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    nixos-hardware = {
      url = "github:NixOS/nixos-hardware/master";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { nixpkgs, nixos-hardware, ... }: {
    nixosConfigurations.rpi4 = nixpkgs.lib.nixosSystem {
      system = "aarch64-linux";
      modules = [
        nixos-hardware.nixosModules.raspberry-pi-4
        ./configuration.nix
      ];
    };
  };
}

With channels, add nixos-hardware and import the matching path:

{
  imports = [
    <nixos-hardware/raspberry-pi/4>
  ];
}

Pin the nixos-hardware revision with the rest of the system inputs rather than following its moving master branch indefinitely.

The stock image enables redistributable firmware. The Pi 4 profile also installs a pinned Wi-Fi and Bluetooth firmware package. The Pi 3 and Pi 5 profiles do not add wireless firmware themselves, so a custom system based only on either profile may need hardware.enableRedistributableFirmware or an explicit firmware package.

Boot process

The official AArch64 image uses this path:

ROM or EEPROM → Raspberry Pi firmware → U-Boot → extlinux.conf → NixOS generation

The Raspberry Pi firmware reads the FAT firmware partition and starts U-Boot. boot.loader.generic-extlinux-compatible generates the extlinux.conf file that U-Boot reads. Its entries provide the NixOS generation menu and rollback support.

Board profiles enable extlinux generation and import the Raspberry Pi firmware module. They do not define a disk layout. When an sdImage module is also imported, the firmware module populates the image's firmware partition automatically. Include U-Boot by setting hardware.raspberry-pi.firmware.uboot.enable. On a running system, firmware-partition updates require hardware.raspberry-pi.firmware.enable.

The nixos-hardware repository does not provide a boot.loader.raspberry-pi module for direct firmware-to-kernel boot. Its firmware module supplies files for the existing U-Boot and extlinux path.[5]

Firmware partition

The hardware.raspberry-pi.firmware module installs Raspberry Pi boot firmware, device trees, overlays, a rendered config.txt, and optionally U-Boot. Custom images use it at build time. On a running system, it acts only when hardware.raspberry-pi.firmware.enable is true. The option is disabled by default.

The stock generic image instead uses the static Nixpkgs firmware population hook. Later nixos-rebuild operations do not refresh its FAT partition. Enable the firmware module when the partition contents must follow the system configuration.

To manage the partition during nixos-rebuild switch, mount its FAT filesystem at /boot/firmware and enable both firmware installation and U-Boot:

{
  hardware.raspberry-pi.firmware = {
    enable = true;
    uboot.enable = true;
  };
}

Set hardware.raspberry-pi.firmware.path if the partition is mounted elsewhere. The activation script checks that the path is a mount point and skips the update with a warning if it is not mounted.

⚠︎
Warning: The firmware module owns the files it copies. On every switch it replaces config.txt, copied device trees, copied overlays, and selected GPU firmware files. It removes stale *.dtb files from the partition root and unrecognised entries under overlays/. Do not keep manual changes or unrelated overlay files in those locations.

The default U-Boot package is pkgs.ubootRaspberryPiAarch64, which covers the 64-bit profiles. A 32-bit Pi 2 configuration must select its matching package:

{ pkgs, ... }:
{
  hardware.raspberry-pi.firmware.uboot = {
    enable = true;
    package = pkgs.ubootRaspberryPi2;
  };
}

This module updates files on the firmware partition. It does not create partitions and does not update the Pi 4 or Pi 5 bootloader EEPROM.

Declarative config.txt

Board profiles generate config.txt from hardware.raspberry-pi.configtxt.settings.[6] Top-level attributes are Raspberry Pi conditional filters such as all, pi4, pi5, and cm4. Lists render the same key more than once.

{ lib, ... }:
{
  hardware.raspberry-pi.configtxt.settings = {
    all = {
      dtparam = [
        "audio=on"
        "i2c_arm=on"
      ];
      dtoverlay = [
        "vc4-kms-v3d"
        "disable-bt"
      ];
      arm_boost = lib.mkForce null;
    };
    pi5.arm_freq = 2400;
  };
}

Booleans render as 1 or 0. Use lib.mkForce null to remove a default. An ordinary assignment supersedes the profile's lower-priority mkDefault list, while equal-priority list definitions may concatenate. Retain any default entries that are still required. To provide a complete custom file instead, set hardware.raspberry-pi.configtxt.file to a path.

Changes reach a running board only when an image builder or the enabled firmware module writes the generated file to the mounted firmware partition.

Kernels and device trees

The generic AArch64 image uses the generic NixOS kernel. The nixos-hardware profiles instead select a pinned kernel from Raspberry Pi's downstream Linux tree. The downstream kernel may support Raspberry Pi-specific hardware that the mainline kernel does not. The mainline kernel follows the normal NixOS update and maintenance path. Choose the kernel that supports the required hardware and test it on the target board.

Two mechanisms apply device-tree overlays:

  • hardware.raspberry-pi.configtxt.settings asks the Raspberry Pi firmware to apply overlays at boot.
  • hardware.deviceTree.overlays merges overlays into kernel device trees while building the system.

The mechanisms can conflict. Loading a generation device tree can discard firmware overlays and runtime fixups, whereas retaining the firmware-provided tree can omit build-time overlays. nixos-hardware issue #1946 tracks work on a single firmware-managed mechanism. Test configurations that use both mechanisms and verify the final device tree seen by Linux.

Operational notes

EEPROM updates

Pi 4 and Pi 5 use a rewritable bootloader EEPROM. Its version and boot order affect USB, network, and NVMe boot behaviour. Use the raspberrypi-eeprom package and follow the official Raspberry Pi bootloader update instructions. Point BOOTFS at the mounted firmware partition when the tool cannot find it automatically.

Updating the EEPROM alone does not provide the complete NixOS boot chain. Released U-Boot 2026.07 cannot read a Pi 5 NVMe device during the extlinux stage. The Pi 5 page describes this limitation.

Wi-Fi power saving

If a board becomes slow or unreachable over Wi-Fi, disable NetworkManager power saving and test again:

{
  networking.networkmanager.wifi.powersave = false;
}

Power supply

Undervoltage can cause storage errors, USB resets, display failures, or unexpected reboots. Use a supply and cable rated for the board and attached peripherals. See the Raspberry Pi power-supply documentation.

No output after U-Boot

Starting kernel ... is normally the last message printed by U-Boot. If the system continues to boot without visible kernel messages, check the kernel console= parameters. Add console=tty0 for display output or configure the serial console used by the board.

Alternative implementations

The nvmd/nixos-raspberrypi project is a separate community implementation for Zero 2 W and Raspberry Pi 3, 4, and 5. It publishes images and a binary cache. Its direct firmware-to-kernel boot path uses matched kernel and firmware bundles. Pi 5-specific modules include separate VC4 and RP1 display paths. Its module API and bootloader are not part of Nixpkgs or nixos-hardware.

The nix-community/raspberry-pi-nix community implementation was archived in March 2025 and is now read-only. For third-party UEFI firmware on Pi 5, see the Pi 5 UEFI notes.

See also

References