Btrfs Basics and Snapshots
Learn Btrfs subvolumes, instant copy-on-write snapshots, and safe system rollback — with both manual btrfs commands and Snapper automation.
Before you start
- ▸Root or sudo access on the target system
- ▸A block device or partition available for Btrfs, or an existing Btrfs mount
- ▸btrfs-progs installed (package name: btrfs-progs on Debian/Ubuntu/Arch, btrfs-progs on Fedora)
Btrfs (B-tree filesystem) ships in the mainline kernel and offers copy-on-write (CoW) semantics, built-in checksumming, transparent compression, and — most useful day-to-day — instant snapshots and subvolumes. Whether you want fine-grained rollback after a bad update or a clean layout for separate @home and @ subvolumes, Btrfs delivers without reaching for LVM or ZFS. This guide walks through creating and managing subvolumes, taking snapshots, and rolling back to a known-good state.
Prerequisites and Quick Orientation
Btrfs is already in the kernel (5.x and 6.x series); no module installation is needed. You need a formatted Btrfs filesystem to follow along. If you're working on an existing installation, many Fedora and openSUSE installs already use Btrfs by default. Ubuntu 24.04 and Debian 12 still default to ext4, but Btrfs is fully supported and installable.
Key mental model: a subvolume is a separately addressable namespace inside one Btrfs filesystem — it looks and mounts like a directory but has its own inode space. A snapshot is just a subvolume that shares CoW extents with its source; no data is duplicated until you modify one side.
Step 1: Format or Identify Your Btrfs Filesystem
If you're starting fresh on a spare partition or disk (e.g. /dev/sdb1), format it:
mkfs.btrfs -L mydata /dev/sdb1
Mount it so you can work with it:
mount /dev/sdb1 /mnt/btrfs-root
To confirm an existing filesystem is Btrfs:
findmnt -t btrfs
Output will list all currently mounted Btrfs volumes; the FSTYPE column will read btrfs.
Step 2: Create Subvolumes
Subvolumes sit inside the Btrfs filesystem tree. A common layout for a root installation uses @ for / and @home for /home, but you can name them anything.
btrfs subvolume create /mnt/btrfs-root/@
btrfs subvolume create /mnt/btrfs-root/@home
btrfs subvolume create /mnt/btrfs-root/@snapshots
List all subvolumes to confirm:
btrfs subvolume list /mnt/btrfs-root
Each subvolume gets a numeric ID. The top-level tree itself has ID 5 and is always present.
Mounting Specific Subvolumes
Mount a subvolume by name with subvol= or by ID with subvolid=:
mount -o subvol=@ /dev/sdb1 /mnt/system
mount -o subvol=@home /dev/sdb1 /mnt/home
For permanent mounts, add entries to /etc/fstab. Use the filesystem UUID rather than the device path:
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx / btrfs defaults,subvol=@,compress=zstd 0 0
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /home btrfs defaults,subvol=@home,compress=zstd 0 0
The compress=zstd option enables transparent compression with a good speed/ratio balance and is safe to add to existing data.
Step 3: Take a Snapshot
Snapshots are read-write by default. Pass -r to make them read-only, which is required if you ever want to send them with btrfs send for backup or replication.
# Read-only snapshot of the @ subvolume
btrfs subvolume snapshot -r /mnt/system /mnt/btrfs-root/@snapshots/system-2025-01-15
# Read-write snapshot (useful for testing changes)
btrfs subvolume snapshot /mnt/system /mnt/btrfs-root/@snapshots/system-test
Snapshots are instantaneous regardless of filesystem size — the kernel simply creates a new subvolume that references the same CoW extents. You'll use disk space only as the two diverge through writes.
Automating Snapshots with Snapper
Manual snapshots get forgotten. Snapper integrates with systemd timers and (on Fedora/openSUSE) with DNF/Zypper to snapshot before and after every package transaction.
Install snapper:
# Debian/Ubuntu
apt install snapper
# Fedora
dnf install snapper python3-dnf-plugin-snapper
# Arch
pacman -S snapper
Create a snapper configuration for your root subvolume (it must already be mounted at /):
snapper -c root create-config /
Enable the systemd timers for hourly, daily, weekly, and monthly cleanup:
systemctl enable --now snapper-timeline.timer snapper-cleanup.timer
List snapshots managed by snapper:
snapper -c root list
Step 4: Inspect Snapshot Differences
Before rolling back, it's worth understanding what changed. Snapper can diff two snapshots:
snapper -c root diff 1..3
Alternatively, use btrfs-diff logic manually by comparing subvolumes as mounted directories with standard tools like diff -rq or rsync --dry-run.
Step 5: Roll Back to a Snapshot
There are two approaches depending on your setup.
Method A: Swap Subvolumes (Manual, No Snapper)
Boot from a live USB or recovery shell. Mount the top-level Btrfs tree (subvolid 5):
mount -o subvolid=5 /dev/sda2 /mnt/btrfs-root
Rename the broken subvolume out of the way, then make the snapshot the new default:
mv /mnt/btrfs-root/@ /mnt/btrfs-root/@.broken
btrfs subvolume snapshot /mnt/btrfs-root/@snapshots/system-2025-01-15 /mnt/btrfs-root/@
Because snapshots are CoW, this is instant. Reboot into the restored system. Once confirmed working, delete the broken subvolume:
btrfs subvolume delete /mnt/btrfs-root/@.broken
Method B: Snapper Rollback (Simpler)
Snapper's rollback command handles the subvolume swap and sets the default subvolume in one step. Run it from a TTY or SSH session (not from within a GUI that has files open in the target subvolume):
snapper -c root rollback 3
Where 3 is the snapshot number from snapper list. Reboot; GRUB (with the grub-btrfs package) or systemd-boot will pick up the new default subvolume automatically on Fedora/openSUSE. On Ubuntu you may need to run update-grub after reboot.
Step 6: Delete Snapshots and Manage Space
CoW means snapshots hold referenced extents alive. Old snapshots consume space incrementally as the live filesystem diverges.
# Delete a single snapshot by path
btrfs subvolume delete /mnt/btrfs-root/@snapshots/system-test
# Delete via snapper (updates its database too)
snapper -c root delete 5
Check actual disk usage broken down by subvolume — df is not useful here:
btrfs filesystem df /
btrfs filesystem usage /
btrfs filesystem usage is the more detailed command and shows allocated vs. used data separately.
Verification
After any rollback or subvolume operation, verify the filesystem is healthy:
btrfs scrub start /
journalctl -f
Scrub reads and checksums every block, reporting errors to the kernel log. Check status while running or after completion:
btrfs scrub status /
Schedule monthly scrubs with a systemd timer (ships with btrfs-progs on most distros):
systemctl enable --now [email protected]
Troubleshooting
- "No space left" despite apparent free space: Btrfs allocates in large chunks and can run out of allocatable space before raw space. Run
btrfs balance start -dusage=50 /to repack sparse data chunks. This can take a while on large filesystems. - Rollback doesn't take effect after reboot: The bootloader may not have the updated default subvolume. Check
btrfs subvolume get-default /and confirm it matches your intended subvolume ID. Re-runupdate-grubor reinstall the bootloader if needed. - Snapper rollback fails with "active snapshot is read-only": Make sure your
@snapshotssubvolume is mounted and writable by root. Check/etc/snapper/configs/rootfor correctSUBVOLUMEandSNAPSHOT_DIRpaths. - Slow performance after many snapshots: A very deep CoW chain (hundreds of snapshots with heavy writes) increases metadata lookup time. Prune old snapshots with
snapper delete --sync 1-50and run a balance pass.
Frequently asked questions
- Does Btrfs support RAID, and is it safe to use?
- Btrfs RAID 0, 1, and 10 for data are considered stable. RAID 5 and 6 have known parity reconstruction bugs and should not be trusted for production data as of kernel 6.x — use mdadm or ZFS for those levels instead.
- How much disk space does a snapshot actually use?
- Immediately after creation, nearly zero — the snapshot shares all CoW extents with the source. Space is consumed only as you write new data to either the source or the snapshot, proportional to how much they diverge.
- Can I convert an existing ext4 filesystem to Btrfs in-place?
- Yes, btrfs-convert can migrate ext4 to Btrfs without a full reformat, and it keeps a rollback subvolume. That said, always back up first; the tool is reliable but any power loss during conversion risks data loss.
- Why does df show plenty of free space but writes are failing?
- Btrfs pre-allocates space in large data and metadata chunks. All chunks can be allocated even when most of the space inside them is unused. Running btrfs balance to repack sparse chunks usually resolves this without deleting any data.
- Is Snapper required, or can I manage snapshots entirely with btrfs commands?
- Snapper is optional. All snapshot operations can be done with btrfs subvolume snapshot and btrfs subvolume delete directly. Snapper adds a database, pre/post transaction pairs, retention policies, and a cleaner CLI for listing and diffing — useful but not mandatory.
Related guides
AI and Artificial-Life Tools on Linux
Set up open-source AI/ML and artificial-life toolkits on Linux: PyTorch, JAX, DEAP, Avida, NetLogo, and RL environments with GPU driver guidance.
Assembly Language on Linux: A Starter Guide
Write x86-64 assembly on Linux from scratch: install NASM and GAS, learn syscalls, assemble and link a working program, then inspect and debug it.
How to Benchmark Disk Performance with fio
Learn to benchmark Linux disk performance with fio: writing job files, testing latency and throughput, and interpreting IOPS and percentile output correctly.
The Linux Boot Process Explained
Trace the full Linux boot sequence from UEFI firmware through GRUB2, the kernel, initramfs, and systemd to your login prompt — with diagnostics at each stage.