Files
Ilan Joselevich f61ff68f63 nixos-init: skip the etc overlay for a non-NixOS init=
find-etc verified the init= was inside a NixOS toplevel and bailed otherwise,
failing initrd-find-etc.service. The etc-overlay mounts require it, so for a
non-NixOS init= (e.g. init=/bin/sh) the initrd dropped to emergency mode before
initrd-init could switch-root into the target.

Make find-etc skip silently for a non-NixOS init=, leaving the /etc-basedir and
/etc-metadata-image symlinks uncreated, and gate the etc-metadata mount, the
/sysroot/etc overlay and the rw-etc service on those symlinks with
ConditionPathExists so they skip instead of fail. initrd-init then switch-roots
into the non-NixOS init directly. The NixOS path is unchanged: the symlinks
exist, so the conditions hold.

Extend the systemd-initrd-non-nixos test with a second node enabling
system.nixos-init.enable, so both the bash initrd-nixos-activation path and the
nixos-init path are covered.

Assisted-by: Claude:claude-opus-4-8
2026-06-16 17:32:17 +03:00
..

nixos-init

A system for the initialization of NixOS.

The most important task of nixos-init is to work around the constraints of the Filesystem Hierarchy Standard (FHS) that are imposed by other tools (most importantly systemd itself).

The primary design principle is to do the minimal work required to start systemd. Everything that can be done later SHOULD be done later (i.e. after systemd has already started). This isn't controversial either, this is the basic principle behind initrds in the first place.

Adding functionality to this init should be done with care and only when strictly necessary. It should always be a last resort. It is explicitly not designed to be extended dynamically by downstream users of NixOS.

The goal of nixos-init is to eventually entirely replace system.activationScripts for booting, enable bashless activation and ultimately make NixOS overall more robust.

Reasoning

  • We already have a native API that can be used to easily extend the system (systemd.services). This is in all ways superior to the stringified and sequential nature of system.activationScripts.
  • For the remaining functionality, a fully fledged programming language makes writing correct software easier and should improve the quality of the NixOS boot code.
  • Most things can be started much later than one might assume. Because systemd services are parallelized, this should improve startup time.

Invariants

For now, this does not try to replace all uses of system.activationScripts. For the first iteration it only tries to offer an alternative to the prepare-root in the systemd initrd.

It never intends to improve or replace scripted initrd. Scripted initrd is being phased out, supporting it is out of scope.

Components

nixos-init consists of a few components split into separate entrypoints. However, these are not separate binaries but a single multicall binary. This allows us to re-use the libc of the main binary and thus reduce the size of the closure. Currently nixos-init comes in at ~500 KiB.

  • initrd-init: Initializes the system on boot, setting up the tree for systemd to start.
  • find-etc: Finds the /etc paths in /sysroot so that the initrd doesn't directly depend on the toplevel, reducing the need to rebuild the initrd on every generation.
  • clear-etc-opaque: Clears stale trusted.overlay.opaque xattrs from the mutable /etc overlay's upperdir before it is mounted, so that lowerdir entries added by a new generation are not hidden.
  • resolve-in-root: Figures out the canonical path inside a chroot.

Future

Current usages of activationScripts:

  1. Initialization of the system 1.1. In initrd 1.2. As PID 1 if there is no initrd (e.g. for containers or cloud VMs).
  2. Re-activation of the system via switch-to-configuration.
  3. Installation of a system with nixos-enter (chroot).

Currently, nixos-init only addresses 1.1. At least 1.2 is also in scope.