All posts
linux

BTRFS + snapshots on Arch Linux / CachyOS: step by step guide

Full tutorial for BTRFS configuration with @ and @home subvolumes, Timeshift and Snapper snapshots, zstd compression. For Arch Linux, CachyOS and Manjaro. Working commands.

5 min readUpdated: June 21, 2026

BTRFS + snapshots on Arch Linux / CachyOS

BTRFS gives you something ext4 does not: system rollback. You installed something that broke Xorg? Go back to 10 minutes ago. Kernel panic after update? Reboot into the previous snapshot. Database corrupted? Restore a file from before the crash.

This guide is my configuration I have used for 3 years on 4 machines (work laptop, home server, test station, VPS).

Installing the system on BTRFS (CachyOS / Arch)

I use a partition layout that gives me full control:

# Partition layout (UEFI + LUKS optional)
# /dev/sda1 - 512MB - EFI partition (FAT32)
# /dev/sda2 - rest  - LUKS encrypted BTRFS

# After installing CachyOS / Arch: create subvolumes
mount /dev/sda2 /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@snapshots
btrfs subvolume create /mnt/@var_log
btrfs subvolume create /mnt/@var_cache

umount /mnt

Why 5 subvolumes, not one? Snapshots copy data. If you have one @ subvolume with /var inside, the snapshot also copies logs and cache. Performance drops, size grows. Separate subvolumes = snapshot only what you want.

Mounting with zstd compression and noatime

Add to /etc/fstab:

# /etc/fstab
UUID=xxxx-xxxx  /              btrfs   subvol=@,compress=zstd:3,noatime,ssd,discard=async  0  1
UUID=xxxx-xxxx  /home          btrfs   subvol=@home,compress=zstd:3,noatime,ssd,discard=async  0  2
UUID=xxxx-xxxx  /snapshots     btrfs   subvol=@snapshots,compress=zstd:3,noatime,ssd,discard=async  0  2
UUID=xxxx-xxxx  /var/log       btrfs   subvol=@var_log,compress=zstd:3,noatime,ssd,discard=async  0  2
UUID=xxxx-xxxx  /var/cache     btrfs   subvol=@var_cache,compress=zstd:3,noatime,ssd,discard=async  0  2
UUID=xxxx-xxxx  /boot/efi      vfat    umask=0077  0  2

Three options that make a difference:

  • compress=zstd:3 — transparent compression. Gain: 10-30% space for free, CPU overhead negligible. Level 3 is the sweet spot (level 1 is faster but compresses less, 9+ gives 2% more for 3x CPU).
  • noatime — do not write the last access time of a file. Gain: fewer writes, longer SSD life. Without this option the kernel updates atime on every read().
  • discard=async — TRIM for SSD in the background, does not block I/O. Alternative: cron with fstrim -A.

Timeshift: desktop snapshots

Timeshift is a GUI + CLI tool that takes snapshots of the whole system (except /home) and restores with one click. Ideal for laptop/desktop.

Installation and configuration

# CachyOS / Arch
sudo pacman -S timeshift

# Initialize (auto-detects BTRFS)
sudo timeshift --snapshot-device /dev/sda2

# Settings:
# - type: BTRFS (not RSYNC — on BTRFS that wastes space)
# - location: subvolume @snapshots
# - schedule: Daily (7 days) + Weekly (4 weeks) + Monthly (3 months)
# - exclude: nothing (Timeshift+BTRFS copies only changes)

First snapshot and restore

# Manual snapshot before a major change
sudo timeshift --create --comments "Before kernel 6.10 update"

# List snapshots
sudo timeshift --list

# Restore from the running system (reboot required)
sudo timeshift --restore

# Restore from GRUB (when the system does not boot)
# Reboot → GRUB → "Arch Linux snapshots" → pick a snapshot

That last point is the key. GRUB integrates with BTRFS — at boot it shows a list of snapshots you can boot from. Kernel panic after pacman -Syu? Reboot, pick yesterday's snapshot, fix, return to the current one.

Snapper: per-transaction snapshots (pre/post pacman)

Snapper is a low-level tool that automatically creates snapshots before and after every pacman operation. Plus a timeline (hourly, daily). It needs more configuration than Timeshift, but gives you precise control.

Configuration for / and /home

sudo pacman -S snapper snap-pac

# Create config for subvolume @
sudo snapper -c root create-config /

# Create config for subvolume @home
sudo snapper -c home create-config /home

# Edit timeline cleanup so you do not bloat
sudo nano /etc/snapper/configs/root
# Change:
#   TIMELINE_LIMIT_HOURLY="10"
#   TIMELINE_LIMIT_DAILY="7"
#   TIMELINE_LIMIT_WEEKLY="4"
#   TIMELINE_LIMIT_MONTHLY="3"
#   TIMELINE_LIMIT_YEARLY="0"

# Enable systemd timers
sudo systemctl enable --now snapper-timeline.timer
sudo systemctl enable --now snapper-cleanup.timer

snap-pac integrates snapper with pacman. From now on every pacman -S creates a "pre" and "post" snapshot automatically. If an update breaks the system:

# List snapshots
sudo snapper list

# Diff between two snapshots
sudo snapper status 42..43

# Restore a single file
sudo snapper undochange 42..43 --filename /etc/fstab

# Restore everything
sudo snapper undochange 42..43

Disabling COW for databases and VMs

BTRFS uses Copy-on-Write — every file modification creates a new block. For databases (PostgreSQL, MySQL, SQLite) this is a performance disaster: instead of one write you get 10. Fix:

# For new files in a directory
chattr +C /var/lib/postgresql/data
chattr +C /var/lib/mysql
chattr +C /var/lib/libvirt/images

# For existing files: you must defragment
btrfs filesystem defragment -czstd /var/lib/postgresql/data

After chattr +C new files do not use COW. Database performance returns to ext4 levels. Snapshots still work (they copy the whole subvolume, not individual COW blocks).

Off-site backup: btrfs send/receive

BTRFS has a built-in incremental backup mechanism — btrfs send and btrfs receive. You send only the delta, not the whole snapshot.

# On the backup server: create subvolume to receive
btrfs subvolume create /backup/laptop/@

# On the laptop: send the first snapshot
sudo btrfs send /.snapshots/1/snapshot | ssh backup@server "btrfs receive /backup/laptop/@"

# Subsequent snapshots: only delta
sudo btrfs send -p /.snapshots/1/snapshot /.snapshots/5/snapshot | \
  ssh backup@server "btrfs receive /backup/laptop/@"

This is 10-100x faster than rsync on large snapshots, because you send only changed blocks. Backing up a 200GB snapshot with 2GB of changes = 2GB transfer, not 200GB.

Monitoring: how much space do snapshots take

# How much space snapshots take
sudo btrfs filesystem du -s /.snapshots/*/snapshot

# Overall disk usage
btrfs filesystem usage /

# How much space you would free by deleting snapshots
sudo snapper list --columns number,description,used-space

Rule: at least 20-30% free space. BTRFS needs free blocks for COW allocation. When you fill the disk 95%+, the system starts failing in non-obvious ways (allocation fails, snapshots stop working, performance drops).

What is next

If you want me to configure BTRFS with snapshots on your existing server (without reinstalling) — get in touch.

Tags:#linux#btrfs#arch#cachyos#snapshot

Najczęściej zadawane pytania

Is BTRFS stable in 2025?
Yes. BTRFS has been stable since kernel 4.x (2017), and in 2025 it is the default filesystem in CachyOS, openSUSE, Fedora Silverblue. Performance issues with COW on databases are solved by disabling COW on database files (chattr +C). For workstations and file servers — a proven choice.
Timeshift vs Snapper — which to choose?
Timeshift: simple, snapshots the whole system, ideal for desktop and laptop. Snapper: granular control (hourly, daily, pre/post pacman), ideal for servers and advanced users. You can have both — Snapper for /, Timeshift for data.
Does BTRFS need defragmentation?
Not in the traditional sense. BTRFS has a 'btrfs filesystem defragment' tool, but you use it to optimize files that were heavily modified (virtual machines, databases). For normal files — leave them. Too frequent defragmentation wears SSD without benefit.
How much space do snapshots take?
BTRFS snapshots are copy-on-write — each modified file is a new block, not a copy of the whole subvolume. A typical desktop with 200GB of data: 10 snapshots = 2-8GB depending on what changed. A snapshot from a fresh install (< 24h) is usually < 1GB. Snapper automatically deletes old snapshots (timeline).

Related posts