ZFS-first Arch Linux installer with ZFSBootMenu and a step-by-step wizard UI.
Note
This is a complete rewrite in Rust. The previous Python version is preserved on the old_python branch.
Tip
Want to understand — or reproduce by hand — what the installer does? docs/zfs-root-install-guide.md walks through the whole procedure command by command, explains why each ZFS property and boot setting was chosen, covers managing several boot environments, and maps the steps onto other distributions.
Setting up ZFS on Arch involves kernel selection, ZFS module installation, bootloader configuration, and optional encryption. Archinstall-ZFS automates these steps with two UI options: a graphical installer (Slint, renders directly via Linux KMS) and a terminal UI (ratatui). It uses direct libalpm bindings for package management (no pacman/pacstrap shell calls), resolves AUR dependency chains via raur/aur-depends, and validates kernel/ZFS compatibility against OpenZFS release data.
Key improvements over the Python version:
- No archinstall dependency — fully standalone, no dependency on the official Arch installer framework or its Python ecosystem
- Single binary with no Python/pip/venv dependencies
- Direct libalpm for all package management with async parallel downloads and per-package progress
- No external package manager binaries needed at runtime (no
pacman,pacstrap,yay) - Proper AUR dependency resolution via
raur+aur-dependscrates - Cancellable installation with graceful cleanup
- Safe LinuxKMS demo for real input, cursor, Wi-Fi, disk, and read-only ZFS testing
- Trace-level file logging (
/tmp/archinstall-zfs.log) for post-mortem analysis
| Disk selection | ZFS configuration | Download progress |
|---|---|---|
![]() |
![]() |
![]() |
| Package installation | ZFS on target | Installation complete |
|---|---|---|
![]() |
![]() |
![]() |
- Download the latest ISO from the releases page.
- Boot on a UEFI machine and connect to the network.
Ventoy users: When selecting the image, choose GRUB2 boot mode for proper UEFI booting.
- Run:
# Graphical UI (Slint, renders directly via Linux KMS — no X11/Wayland needed)
azfs
# or Terminal UI (ratatui)
azfs-tuiWhy recommended: the ISO already contains ZFS components and both installers, so startup is faster and avoids on-the-fly package installation.
The ISO boot menu also offers Arch Linux installer — safe LinuxKMS demo. It runs the same Linux KMS, software Skia, libinput, cursor, touchpad, and iwd paths as the real graphical installer, while disabling installation and every destructive storage operation. Disks and partitions remain visible and every configuration step can be exercised.
The demo can discover ZFS pools and explicitly import one for inspection with
zpool import -N -o readonly=on -o cachefile=none. It never mounts datasets,
verifies the pool's readonly property after import, and exports only pools
that were imported by the current demo session. Those pools are exported when
the user requests it and again during normal application shutdown. The same
mode can be selected manually with azfs --demo.
# Boot the official Arch ISO and connect to the network
# Download binaries from the latest release
curl -LO https://github.com/okhsunrog/archinstall_zfs/releases/latest/download/azfs-tui
curl -LO https://github.com/okhsunrog/archinstall_zfs/releases/latest/download/azfs
chmod +x azfs-tui azfs
# For the GUI, install runtime dependencies first:
pacman -Sy libxkbcommon libinput freetype2 fontconfig ttf-dejavu
# Run
./azfs # or ./azfs-tuiNote: This path installs ZFS components during the run, so it usually takes longer than Option A.
azfs-tui --config config.json --silent
# If the exported config needs passwords:
azfs-tui --config config.json --secrets config.secrets.json --silentSaved configurations omit the ZFS encryption password, root password, and user
passwords. The TUI can optionally save those values to a separate JSON file
with mode 0600; pass that file with --secrets for unattended installs.
Legacy configuration files containing inline passwords remain supported.
| Mode | Description | Best for |
|---|---|---|
| Full Disk | Complete disk takeover with automated partitioning. Clears GPT/MBR signatures, creates fresh GPT table, partitions (EFI 500MB, optional swap, remainder for ZFS) | Clean installs, single-purpose machines, maximum automation |
| New Pool | Creates ZFS pool on an existing partition. Uses your existing partition layout, creates ZFS pool on selected partition | Dual-boot scenarios, custom partitioning schemes, preserving existing OS installations |
| Existing Pool | Installs into an existing ZFS pool as a new boot environment. Creates new BE datasets within your existing pool structure | Experiments, testing different configurations, multiple Arch installations |
Pro tip: Existing Pool mode is excellent for trying different desktop environments or system configurations without risk — each installation becomes its own boot environment selectable from ZFSBootMenu.
linux-lts+zfs-linux-ltslinux+zfs-linuxlinux-zen+zfs-linux-zenlinux-hardened+zfs-linux-hardened
All kernel options automatically fall back to
zfs-dkmsif precompiled modules are unavailable.
One of the key challenges with ZFS on Arch is compatibility between kernel versions and ZFS modules. The installer includes a validation system that:
- Parses OpenZFS releases: Checks https://github.com/openzfs/zfs/releases for supported kernel version ranges
- Validates current packages: Cross-references with actual kernel versions available in Arch repositories
- Checks precompiled availability: Determines if precompiled ZFS modules exist for your chosen kernel
- Assesses DKMS feasibility: Analyzes whether DKMS compilation will work with bleeding-edge kernels
- Downloads archzfs.db directly: Falls back to the archzfs package database when the repo isn't configured locally
- Provides smart fallbacks: Automatically suggests compatible alternatives when conflicts are detected
The validation runs in two places:
- In the TUI/GUI — shows compatibility status (
[OK]/[INCOMPATIBLE]) next to each kernel - Before installation — warns about potential issues in Phase 0
- Pool-wide encryption (all datasets inherit)
- Per-boot environment encryption (encrypts the base dataset)
- No encryption
No swap + ZRAM (recommended): Compressed swap in RAM via systemd-zram-generator. Default size: min(ram / 2, 4096) MB. zswap is disabled to avoid double compression.
Swap partition: Dedicated partition with zswap enabled. Supports encryption via cryptswap in /etc/crypttab.
No swap: Pure RAM-only operation.
Swap on ZFS (zvol/swapfile) is not supported due to potential deadlock issues. Hibernation is not currently supported.
Boot Environments (BE) are a way to maintain multiple independent systems on a single ZFS pool. Each system is housed in its own root dataset and can be selected at boot through ZFSBootMenu.
ZFSBootMenu is a bootloader designed specifically for ZFS. Unlike traditional bootloaders, it natively understands ZFS structure and can display boot environments in a menu, create snapshots, and clone boot environments directly at boot time.
pool/prefix/root → / (root filesystem, canmount=noauto)
pool/prefix/data/home → /home (user data)
pool/prefix/data/root → /root (root user data)
pool/prefix/vm → /vm (virtual machines)
ZFSBootMenu is built locally via generate-zbm (AUR package) with a pacman hook for automatic regeneration on kernel updates.
A custom ZED hook (history_event-zfs-list-cacher.sh) ensures only the current boot environment's datasets are mounted, preventing cross-environment mount conflicts. It is installed to /etc/zfs/zed.d/ and marked immutable (chattr +i) to survive ZFS package updates. See the installation guide for how it decides what belongs to the running environment.
- Resolves full AUR-to-AUR dependency chains via
raur+aur-depends - Builds using a temporary user (
aurinstall) with temporary passwordless sudo - Cleans up temp user and build artifacts after installation
Profiles bundle a desktop environment, window manager, or server role with the packages, services, display manager, and post-install hooks needed to make it work end-to-end. Both the TUI and GUI ask follow-up questions only when they're actually relevant: a desktop profile prompts for optional packages, display manager override, and (for Wayland compositors) seat access; a server profile skips all of those.
One profile per install. Unlike upstream archinstall you can't compose several profiles in one run (no
gnome + i3orsshd + docker + postgresqlin a single pick). If you need a combination, choose the closest profile and add the extras through the Extra packages picker, plus Extra services for any units that need enabling. We trade composition for simpler reproducibility — your config JSON always names exactly one profile.
The profile-scoped settings live inside a profile_selection block in the
config JSON, and switching profiles atomically replaces the whole block so
stale fields can never leak between selections:
{
"profile_selection": {
"profile": "hyprland",
"optional_packages": ["hyprpaper", "hyprlock", "wl-clipboard"],
"display_manager_override": null,
"seat_access": "seatd"
},
"gfx_driver": "nvidia_open"
}GPU driver, audio server, and Bluetooth stay top-level because they're useful on headless installs too. The GPU driver picker is hidden for non-graphical profiles, and selecting the proprietary NVIDIA driver with a Wayland-only compositor surfaces a warning (TUI shows a confirmation, GUI an inline notice).
- zrepl support for automatic snapshot creation and retention
- Schedules: 15-minute intervals with tiered retention (4x15m, 24x1h, 3x1d)
- Generates configuration based on your pool and dataset prefix
archinstall_zfs/
core/ # Library crate — all installation logic, config, validation
tui/ # ratatui-based terminal UI (wizard-style, 7 steps)
slint-ui/ # Slint GUI (Linux KMS backend, wizard-style)
xtask/ # Development tasks (QEMU testing, ISO building)
gen_iso/ # ISO building templates and scripts
All package installation uses direct libalpm bindings (alpm crate):
AlpmContext::for_host()— installs packages on the live ISOAlpmContext::for_target()— installs packages into the target chrootTargetMounts— manages API filesystem mounts (proc/sys/dev) matching pacstrap'schroot_setup()- Async download engine with parallel downloads, per-package progress, SHA256 verification, and mirror failover
The only remaining shell calls are:
pacman-keyfor GPG keyring operations (no libalpm equivalent)makepkgfor building AUR packages (bash script by design)chroot_cmdfor non-package chroot commands
Two supported workflows depending on the host distro. Pick one.
Everything runs directly on the host. No containers needed for builds.
# one-time setup
sudo pacman -S --needed \
rust pacman pkgconf clang base-devel just \
libxkbcommon libinput libdrm freetype2 fontconfig ttf-dejavu \
archiso pacman-contrib qemu-base qemu-img edk2-ovmf
# daily
just cargo-build # native cargo build, produces target/release/{azfs,azfs-tui,xtask}
just cargo-test
just iso-test # native mkarchiso (sudo)
just iso-full
just zfs-be-build # writable bare-metal LinuxKMS demo BE on novafs
just test-install # QEMU regression test (requires cargo-build first)
just qemu-install # interactive boot of latest ISOThe full ArchISO profile can also be deployed as a normal writable ZFSBootMenu boot environment. This is useful for testing LinuxKMS, libinput, touchpads, cursors, real GPUs, and iwd on physical hardware while keeping installation and destructive storage operations disabled.
# Defaults to novafs/archiso0/root, linux-lts, and the precompiled ZFS package.
just zfs-be-build
# All important choices can be overridden explicitly.
just zfs-be-build --mode dkms --kernel linux \
--dataset tank/archiso0/root --mount-dir /mnt/archzfs-beThe command uses mkarchiso to assemble the full package/profile environment,
then copies its staging root into a new dataset with numeric ownership, ACLs,
and xattrs preserved. It replaces the live-media initramfs with a normal ZFS
root initramfs, configures mountpoint=/, canmount=noauto, and overlay=off,
adds archinstall_zfs.demo=1 (and rw when no read-write policy is
inherited from the current root's command line) to the ZFSBootMenu command
line, and creates a @fresh snapshot. The pool's bootfs property is not
changed. The initramfs is built with mkinitcpio's autodetect hook, so build
it on the machine that will boot it; a pool moved to different hardware may
be missing drivers.
The root-owned staging tree defaults to /var/tmp/archinstall-zfs-be-workdir
so desktop file indexers cannot keep the temporary chroot mounts busy. Set
ARCHINSTALL_ZFS_BE_WORKDIR to override it.
For safety, deployment refuses to reuse an existing dataset. It also refuses a
staging tree after recursive chown, since that would lose root ownership.
After booting the new environment, tty1 automatically logs in as root (the
live profile's autologin is kept); run azfs or azfs-demo.
Builds run inside the CI container image, which has all the Arch-specific
deps (libalpm, archiso, …) pre-installed. Everything produces
Arch-glibc binaries, so artifacts are portable to the ISO.
# one-time setup (Fedora example; use the equivalent on other distros)
sudo dnf install -y nix nix-daemon podman qemu-system-x86 qemu-img edk2-ovmf
sudo systemctl enable --now nix-daemon
just builder-pull # pull the CI image (~2 GB, one-time)
# Optional: auto-enter nix dev shell on cd (recommended for editor LSP)
# Requires `direnv` + `nix-direnv` installed.
echo 'use flake' > .envrc && direnv allow
# daily
# Inside the nix shell (auto-entered by direnv, or run `nix develop`):
cargo check / cargo test / cargo run # fast native iteration, rust-analyzer-friendly
# For artifacts (binaries or ISOs):
just cargo-build-container # Arch-glibc target/release/{azfs,azfs-tui,xtask}
just iso-test-podman # container-backed mkarchiso
just iso-full-podman
just test-install # QEMU regression test (requires cargo-build-container first)
just qemu-install # qemu runs on host either wayjust lint # Run clippy
just fmt # Format code
just ssh # SSH into running QEMU VM
just upload # Upload binaries to running VM
just builder-info # Inspect podman image + cache volumes (option 2)
just builder-clean # Remove podman image and cache volumesThe xtask test suite boots a QEMU VM, runs the installer, reboots from the installed disk, and verifies 13 system health checks (kernel, ZFS pool, sshd, fstab, initramfs, zram, mounts, hostid, ZED hook, bootfs, rootprefix, ZBM build, ZBM pacman hook).
Installer logs are automatically pulled from the VM to test-install.log for analysis.
Runs share a package and source cache on the host (/var/tmp/archinstall-zfs-cache, --cache-dir to move it, --no-cache to skip it), so the ~1 GB of packages and the ZFSBootMenu tarball are downloaded once rather than on every run. The installer picks the cache up from ARCHINSTALL_ZFS_PKG_CACHE and ARCHINSTALL_ZFS_SRCDEST, which also makes an installation from a prepared cache possible outside the tests.
ZFS package dependency issues
If a precompiled ZFS package for your exact kernel version is not available, the installer automatically falls back to DKMS. The kernel compatibility validation reduces the chance of encountering build failures.
Installation fails in QEMU
Common causes:
- UEFI not enabled in VM settings
- Insufficient RAM (< 2GB)
- No network connectivity
Tips:
- Use
just qemu-install-serialfor better error visibility - Check
test-install.logfor detailed trace-level logs - Verify UEFI firmware is loaded
Boot issues after installation
If ZFSBootMenu does not appear:
- Check UEFI boot order in firmware
- Verify the EFI partition is mounted
- Confirm ZFSBootMenu files exist in
/boot/efi/EFI/ZBM/
Recovery: Boot from the installer USB and run repair commands via chroot.
- Meet archinstall_zfs: The TUI That Tames Arch Linux ZFS Installation (English)
- Arch Linux on ZFS for humans: archinstall_zfs (Habr, Russian)
- Arch Linux on ZFS for humans: archinstall_zfs (Russian)
- ZFS root installation guide — the full manual procedure and the reasoning behind every choice
- Debugging boot issues — diagnosing a system that does not come up after install
- Arch Wiki: ZFS
- Arch Wiki: Install Arch Linux on ZFS
- ZFSBootMenu: Boot Environments and You
- OpenZFS Documentation
GPL-3.0 — see LICENSE.






