/persistence

Everything is rebuilt. Your files are kept.

At every boot / starts again from an empty snapshot and is filled from the config. Your home folder, and the short list of system paths that have to outlive a reboot, live on /persist and are mounted back into place.

01Lifecycle

What happens at every boot.

  1. 01firmware

    Boot loader

    systemd-boot

    Loads the kernel and initrd from the ESP. A key during the 3-second menu picks an older system; five are kept.

  2. 02initrd

    Unlock

    systemd-cryptsetup@cryptroot

    Asks for the passphrase in your keyboard layout and opens the LUKS2 volume.

  3. 03initrd

    Reset /

    rollback.service

    Before / is mounted: deletes subvolumes nested in root, then root, and snapshots root-blank in its place. Writes this boot’s id to /.root-reset.

  4. 04initrd

    Mount

    sysroot.mount

    The fresh root is mounted, with /nix, /persist and /var/log, which are needed for boot.

  5. 05system

    Bind kept paths

    impermanence

    Every declared directory and file is bind-mounted from /persist into place. tmpfiles sets secret permissions again.

  6. 06system

    Verify

    root-reset-check.service

    Compares /.root-reset with the boot id. If / wasn’t reset, the unit fails, and ephemeral-doctor says so and how to fix it.

Every boot, in order. The reset is in modules/ephemeral-root.nix; the kept paths in modules/persist.nix and the file of each feature.

02Kept and lost

Three places outlive a reboot.

/persist subvolume

Bind-mounted into /: /home and every declared path below. Also read directly from here: the machine's flake, the login password hash, the SSH host key, root-only secrets and the snapshots.

/nix subvolume

The Nix store: every installed package and system generation. Never reset; old generations are collected weekly after 30 days.

/var/log subvolume

The journal and logs, so journalctl -b -1 still works after a reboot.

Everything else on / is gone at the next boot: a file you edited in /etc, a database a program created in /var/lib, a cache in /root. /tmp is a tmpfs, so it's cleared too.

Kept by default

FromPathsDeclared in
Every machine
  • /home
  • /var/lib/nixos
  • /var/lib/AccountsService
  • /var/lib/systemd/backlight
  • /var/lib/systemd/rfkill
  • /var/lib/systemd/timers
  • /var/lib/systemd/linger
  • /var/lib/systemd/timesync
  • /etc/machine-id
  • /var/lib/systemd/random-seed
  • /var/lib/systemd/credential.secret
persist.nix
Networking
  • /var/lib/NetworkManager
  • /etc/NetworkManager/system-connections
networking.nix
Hardware
  • /var/lib/bluetooth
  • /var/lib/fwupd
hardware.nix
Every desktop
  • /var/lib/cups
  • /var/lib/containers
  • /var/lib/flatpak
printing.nix, podman.nix, flathub.nix
The login screen
  • /var/lib/gdm (GNOME)
  • /var/lib/plasmalogin (Plasma)
  • /var/lib/noctalia-greeter (niri, Umbriel)
desktop/
Options, when on
  • /var/lib/opensnitch
  • /var/lib/tailscale
  • /var/lib/fprint
opensnitch.nix, tailscale.nix, fingerprint.nix
Apps, when picked
  • /var/lib/docker (Docker)
  • /var/lib/libvirt, /var/lib/swtpm-localca (virt-manager)
apps/

Read from modules/ at config v4.1.0. A machine's own list is in /etc/ephemeral/kept:

shell
ephemeral-doctor kept        # everything kept across reboots
sudo ephemeral-doctor lost   # what the next reboot removes, written since this boot

03Over time

Reboots, rebuilds, rollbacks and reinstalls.

rebootrebuild or updateolder systemreinstall
/ outside what's keptgonekept until the next rebootgonegone
/homekeptkeptkeptgone
the other kept pathskeptkeptkept, but not mounted if that system doesn't keep themgone
/var/log, snapshots of /persistkeptkeptkeptgone
installed packages (/nix)keptkeptkeptreinstalled

04Keeping more

Declare a path, rebuild, and it's kept from then on.

Save this as /persist/etc/nixos/modules/keep.nix with your own paths and run ephemeral-update. Apps from ephemeral-apps already keep what they need.

What was in a path before isn't copied over. If you need it, copy it to /persist first, to /persist/var/lib/postgresql for the example.

Taking a path off the list doesn't delete anything: its files stay in /persist, no longer mounted. The same goes for an app you unpick that kept data, such as Docker. Snapshots still hold a copy for up to four weeks, so the space comes back as they expire.

modules/keep.nix
{
  flake.modules.nixos.pc.environment.persistence."/persist" = {
    directories = [ "/var/lib/postgresql" ];
    files = [ "/etc/machine-info" ];
  };
}
finding what's left
sudo du -sh /persist/var/lib/*
sudo rm -rf /persist/var/lib/docker

05Protecting your files

Snapshots for mistakes, backups for disasters.

On the full profile, snapper takes read-only snapshots of /persist, and with it your home folder: 24 hourly, 7 daily and 4 weekly. A deleted or broken file can be copied back from one. Only root can read them, because old snapshots still contain old password hashes and keys.

Snapshots are on the same disk, so a reinstall, a dead disk or a lost laptop takes them too. Keep a copy elsewhere: your home folder with Vorta or Pika Backup, the machine's settings and secrets with ephemeral-backup, the config in a private git repo, and the LUKS header once with luks-header-backup. Backups and snapshots has the commands.

06Before you install

Your responsibilities.

  • 01

    Files go in your home folder. Anything a program writes outside /home and the kept list disappears at the next boot. Check with sudo ephemeral-doctor lost before rebooting if you're unsure.

  • 02

    System state you want to keep has to be declared. A service you set up by hand, a database, an edited file in /etc: put it in a module, or it won't survive.

  • 03

    passwd doesn't stick. Users are declared by the config. Change your password with ephemeral-passwd.

  • 04

    Snapshots aren't backups. Back up your home folder and run ephemeral-backup to another disk.

  • 05

    Secrets don't go in /persist/etc/nixos. Everything there is copied into the world-readable Nix store at every rebuild. Keep them in /persist/etc/<name>, root-owned, mode 600.