ZFS boot environments
illumos ships a native atomic-upgrade story that predates and closely mirrors
NixOS’s generations: boot environments (BEs), managed with beadm. A boot
environment is a bootable clone of the root filesystem living on its own ZFS
dataset. solnix maps each Nix generation onto a boot environment, so the
mental model you already have from NixOS transfers almost directly.
On illumos generally
beadmand ZFS boot environments are mature and are how every illumos distribution does upgrades and rollback. On solnix the generation-to-BE mapping in the activation path is planned (there is no bootable image yet — see Introduction); thebeadmcommands below are the real illumos commands and work on any illumos host.
The NixOS analogy (read this first)
If you run NixOS, you already understand boot environments — they are the same idea with a different mechanism:
| NixOS on Linux | solnix on illumos |
|---|---|
Generation (a /nix/store system closure) | Nix generation → one ZFS boot environment |
nixos-rebuild switch | build config → create + activate a new BE |
| GRUB submenu of past generations | boot loader menu of past BEs |
| Roll back = pick an older generation | Roll back = beadm activate an older BE, or pick it at boot |
nix-collect-garbage frees old generations | beadm destroy removes old BEs |
| Copy-on-write nothing (store paths shared) | ZFS clones share blocks (cheap) |
The important difference: on Linux the bootloader points at a kernel + initrd + store path; on illumos the bootloader points at a whole bootable root dataset (the BE). ZFS makes that whole-root switch as cheap as NixOS’s per-path sharing, because a new BE is a clone, not a copy.
What a boot environment is
A BE is a ZFS dataset (under rpool/ROOT/ by convention) containing a complete,
bootable root filesystem. Because ZFS clones are copy-on-write, creating a new
BE from the running one:
- costs almost no space initially (blocks are shared),
- is near-instant,
- leaves the current BE completely untouched and independently bootable.
You can have many BEs on one pool. Exactly one is active (the default boot target); you can also boot a non-active BE once without changing the default.
The beadm commands
List
beadm list
BE Active Mountpoint Space Policy Created
solnix-1 N / 8.1G static 2026-01-10 09:14
solnix-2 NR / 2.3G static 2026-01-12 11:02
The Active column: N = active now (the running BE), R = active on reboot
(the default boot target), NR = both. beadm list -a shows the datasets and
snapshots that make up each BE.
Create
pfexec beadm create solnix-3 # clone the running BE
pfexec beadm create -e solnix-1 solnix-3 # clone from a specific BE
Creating a BE does not activate it — the running system is unaffected.
Activate
pfexec beadm activate solnix-3
Sets solnix-3 as the default boot target (R). It takes effect on the next
reboot; the current system keeps running until then. This is the atomic switch:
nothing on the live root is mutated.
Boot once without activating
At the boot loader menu you can select any BE for a single boot without making
it the default — the illumos equivalent of picking an old NixOS generation from
the GRUB submenu. If it works, beadm activate it; if not, reboot back to the
default.
Destroy
pfexec beadm destroy solnix-1
Removes a BE and its datasets. You cannot destroy the currently running BE. This is the analog of garbage-collecting old NixOS generations.
Mount / unmount (inspect without booting)
pfexec beadm mount solnix-3 /mnt
# inspect /mnt ...
pfexec beadm unmount solnix-3
Useful for comparing two generations or repairing one from another.
Snapshots and BEs
A BE is built on ZFS snapshots and clones (see ZFS storage). Two things follow:
- Creating a BE takes a snapshot of the source root and clones it. The snapshot is what makes the operation cheap and instant.
beadm create solnix-3@backup(name with@) creates a snapshot of a BE rather than a new BE — a point-in-time marker you can later turn into a BE.
Because it is all ZFS underneath, the same integrity, zfs send/receive, and
scrub guarantees that protect your data protect your boot environments too.
Safe upgrade and rollback, end to end
The upgrade cycle solnix targets, framed the NixOS way:
- Build a new system configuration → a new Nix generation.
- Create a boot environment for that generation (
beadm create). - Populate the new BE with the generation’s closure.
- Activate the new BE (
beadm activate) — a boot-target change, not an in-place mutation. - Reboot into the new generation. The previous BE remains bootable and untouched.
- Roll back if needed: boot the previous BE from the loader menu, or
beadm activateit and reboot. No packages to reinstall, no state to unwind — you are back on the exact prior root.
The properties that make this worth it:
- Atomic — the switch is a single pointer change; a power loss mid-upgrade leaves you on the old, intact BE.
- Instant rollback — the previous root is right there, bootable.
- Cheap — clones share blocks, so twenty generations do not cost twenty full roots.
Boot loader integration
illumos on x86 uses the loader (the FreeBSD-derived boot2/loader,
replacing the older GRUB on modern distributions); SPARC uses OpenBoot. Either
way, beadm activate updates the loader’s default and the menu lists the
available BEs, so choosing an older generation at boot is a menu selection. This
is the mechanism illumos already ships and trusts — solnix reuses it rather than
inventing a bootloader story.
Further reading
beadm(8)— the command reference.- ZFS storage — the snapshots and clones BEs are built on.
- How solnix is built — how generations map into the system.
- Further reading & resources — canonical ZFS/BE admin guides.