Docs β†’ Existing install β†’ ZFS root

Already running Omarchy? Getting to a ZFS root

You have a working Omarchy install on btrfs and you want ZFS underneath it. Here is what is possible, the two routes that work, and how to keep your current install bootable while you move.

There is no in-place btrfs β†’ ZFS conversion

btrfs and ZFS are different on-disk formats. No tool rewrites one into the other, and anything claiming to "convert" your root filesystem is either copying data elsewhere first or about to lose it. Every real route below moves your data to a new pool and reinstalls the operating system.

That sounds worse than it is. On Omarchy Quattro almost nothing you care about lives outside /home: the shell, themes, keybindings and Quickshell config are all in ~/.config and ~/.local/share/omarchy, and the OS itself is just packages. A reinstall plus a restore is usually a 45-minute job, and you end up on a filesystem you can snapshot and roll back forever after.

RouteYou needDowntimeSafety net
A. Reinstall & restore One disk + an external drive for the backup The whole job; the machine is unusable in between Your backup. That is all. Verify it before you start.
B. Second disk A spare internal disk (or an M.2 slot free) Minutes. You boot back into the old install any time The old install stays intact and bootable until you erase it.

Take route B if you have any way to add a disk. Being able to boot the old system while the new one settles in is worth more than the cost of the drive.

1. Confirm what you are on

findmnt -no FSTYPE /            # btrfs, probably
pacman -Q omarchy               # must be a Quattro (4.x) version
[ -d /sys/firmware/efi ] && echo UEFI || echo "BIOS. ZFSBootMenu needs UEFI"
mokutil --sb-state              # want: SecureBoot disabled
lsblk -o NAME,SIZE,MODEL,TRAN,MOUNTPOINTS

If pacman -Q omarchy reports nothing, you are on a pre-Quattro curl | bash install. Upgrade to Quattro first, on btrfs, and get that working before adding ZFS to the pile.

2. Capture the install

Do this even on route B, where you keep the old disk. It takes minutes and it is the difference between an afternoon and a bad week.

Your data

# Everything of yours, permissions and ACLs intact.
sudo rsync -aHAX --numeric-ids --info=progress2 \
     /home/ /run/media/$USER/backup/home/

The shape of the system

mkdir -p ~/migration && cd ~/migration

pacman -Qqe          > pkgs-explicit.txt     # what you asked for
pacman -Qqm          > pkgs-foreign.txt      # AUR / local packages
systemctl list-unit-files --state=enabled > units-enabled.txt
sudo cp -r /etc/NetworkManager/system-connections wifi-and-vpn
timedatectl show     > timedate.txt
localectl status     > locale.txt
crontab -l           > crontab.txt 2>/dev/null || true

Copy ~/migration to the external drive too.

What not to restore

/etc/fstab, /etc/mkinitcpio.conf and anything bootloader-related belong to the old layout. Restoring them onto a ZFS root is how people end up in an emergency shell. Let the new install own boot configuration; bring back your data and your app config, not the plumbing.

3. Install root-on-ZFS

Both routes use the ISO from route 1. Follow that page for the download, the USB stick, the 15-second question and the installer's prompts. The only difference is which disk you point it at.

Route A. Same disk

Verify the backup from another machine or a live USB first: mount it, open a few files, check the sizes look sane. Then install to the disk and erase the old system. Point of no return; there is no undo.

Route B. Second disk, old install untouched

  1. Shut down, fit the new disk, boot the ISO.
  2. At the disk selection step, pick the new disk. Read the destructive-confirmation list carefully. It names the exact devices, and this is the moment to catch a mix-up.
  3. Install as normal, using the same username as before so restoring /home/<user> lands with the right ownership.
Both disks now have an EFI partition

Your firmware will have entries for Limine (old install) and ZFSBootMenu (new one). omarchy-zfs keeps ZFSBootMenu first in the EFI boot order on every package transaction, but it only ever reorders. It never deletes another bootloader's entry, because which systems stay bootable is your call. So the old install remains one firmware-menu keypress away. Check with efibootmgr.

4. Restore your data

Log into the new system once so the account and its home dataset exist, then restore into it. On route B the old disk is right there:

# Route B: mount the old btrfs root read-only and copy from it
sudo mkdir -p /mnt/old
sudo mount -o ro /dev/nvme1n1p2 /mnt/old        # your old root partition
sudo rsync -aHAX --numeric-ids --info=progress2 \
     /mnt/old/home/pete/ /home/pete/

# Route A: same thing, from the external drive
sudo rsync -aHAX --numeric-ids --info=progress2 \
     /run/media/pete/backup/home/pete/ /home/pete/
Make sure /home is really mounted first

Use mountpoint -q /home && echo mounted, not findmnt /home. findmnt reports the nearest enclosing mount, so it answers "mounted" for a plain directory. If you rsync 200 GB into /home while its dataset is unmounted, the data lands in the root dataset and vanishes under the real mount at the next boot.

Fix ownership if the UID changed, then put the packages back:

sudo chown -R pete:pete /home/pete

# Repo packages you had explicitly installed
sudo pacman -S --needed - < ~/migration/pkgs-explicit.txt

# AUR packages, via your helper
yay -S --needed $(cat ~/migration/pkgs-foreign.txt)

# Network connections
sudo cp -r ~/migration/wifi-and-vpn/* /etc/NetworkManager/system-connections/
sudo chmod 600 /etc/NetworkManager/system-connections/*
sudo systemctl restart NetworkManager

Expect pkgs-explicit.txt to contain a few packages that no longer exist or now come from a different repo. Read pacman's complaints rather than forcing past them.

5. Take the first snapshot

You are on ZFS now. Use it before you customise anything:

sudo zfs snapshot -r zroot@migrated
zfs list -t snapshot

From here on, every package transaction takes a pre-upgrade snapshot automatically, and ZFSBootMenu can roll back to any of them from before the OS starts.

Retiring the old disk (route B)

Live on the new install for a week or two first. When you are ready, either wipe the old disk and add it as a mirror of your pool:

# Same-size or larger disk. This makes zroot self-healing.
sudo zpool attach zroot /dev/disk/by-id/<existing> /dev/disk/by-id/<old-disk>
zpool status zroot        # watch it resilver

…or keep it as a local backup target and replicate to it:

sudo zpool create -o ashift=12 -O compression=zstd -O mountpoint=none backup /dev/disk/by-id/<old-disk>
sudo zfs snapshot -r zroot@$(date +%F)
sudo zfs send -R zroot@$(date +%F) | sudo zfs receive -u -d backup

If you attach it as a mirror, remember the old EFI partition is gone. Re-check efibootmgr and keep at least one working ZFSBootMenu entry.

Why not do it in place?

People ask whether they can shrink btrfs, build a pool in the freed space, copy the system across, and switch. It is technically possible and it is a bad trade: you are doing a live copy of a running system, then hand-assembling the parts the installer would have got right. The hostid inside the initramfs, the zfs mkinitcpio hook ordering, the ESP contents, the ZFSBootMenu EFI entry and the boot-environment layout. Each one is a silent unbootable-system bug if you get it slightly wrong, and you will be debugging it with no working machine. The ISO automates exactly that list, and a second disk costs less than the evening you would spend.

Alternatives worth considering