The update broke your system
You run sudo dnf upgrade --refresh on a Friday afternoon. The terminal finishes, you reboot, and the desktop environment refuses to start. The login screen loops back to itself, or the system drops to an emergency shell. You spent hours configuring your environment, and a single package update wiped it out. This is exactly why Fedora ships with Btrfs and Snapper by default. You do not need to rebuild your system from scratch. You can step back in time.
How Btrfs and Snapper interact
Btrfs is a copy-on-write filesystem. When you modify a file, Btrfs does not overwrite the old data in place. It allocates new blocks for the changed data and updates the metadata pointers. The old blocks remain on disk until they are explicitly freed. Snapper leverages this behavior to take instantaneous snapshots. A snapshot is just a read-only pointer to the exact state of the filesystem at a given moment. It takes zero extra disk space until you start writing new data.
Think of it like a version control system for your entire root partition. Git tracks changes to your source code. Snapper tracks changes to your operating system. Fedora automatically triggers Snapper before and after every dnf transaction. The pre-snapshot captures the working state. The post-snapshot captures the updated state. If the update introduces a regression, you simply tell Snapper to restore the pre-snapshot. The filesystem pointers shift back, and your system boots exactly as it did before the transaction.
Btrfs tracks shared blocks across snapshots. If you have ten snapshots and only change one configuration file, the disk usage increases by the size of that single file. The rest of the filesystem remains shared. This makes frequent snapshots cheap. You do not need to worry about filling your disk by taking checkpoints before every risky operation.
Run btrfs filesystem usage / to see how shared blocks are calculated. The Data, single row shows space used exclusively by the current subvolume. The Data, DUP row shows space shared across snapshots. Trust the numbers. Manual disk calculations are wrong.
The automatic pre and post workflow
The default configuration handles routine updates without intervention. Snapper hooks into the dnf transaction lifecycle. When dnf begins downloading packages, Snapper takes a pre-snapshot. When dnf finishes installing and running post-install scripts, Snapper takes a post-snapshot. Both snapshots are tagged with the transaction ID and a timestamp.
You can view the entire history with a single command. The output shows the snapshot ID, type, date, and the exact dnf command that triggered it.
Here is how to list all snapshots and identify the transaction history:
sudo snapper list # Queries the default root config and prints the snapshot table
sudo snapper status 15 16 # Compares pre and post snapshots to show exact file changes
sudo snapper diff 15 16 # Shows a unified diff of modified files between two snapshots
The status command prints a concise list of added, modified, and deleted files. The diff command outputs a full patch-style view. Use diff when you need to understand exactly which configuration file broke your service. Do not guess which package caused the regression. Read the diff first.
Creating manual checkpoints
The automatic workflow covers package manager operations. It does not cover manual edits, compiled software, or third-party installers. You will still need to create manual snapshots before risky operations. Compiling a custom kernel, installing experimental drivers, or modifying system services all warrant a checkpoint.
Here is how to create a manual snapshot with a descriptive label:
sudo snapper create -d "Pre-kernel-compile checkpoint" # Creates a read-only snapshot of the root subvolume
sudo snapper list # Displays all snapshots with their IDs, types, and timestamps
sudo snapper list --number-only # Prints only the IDs for scripting or quick reference
The output will show a table. The # column is the snapshot ID. The Type column shows single, pre, or post. The Date and Description columns help you identify the right restore point. Do not rely on memory. Use the description field consistently.
You can also mount a snapshot to inspect its contents without rolling back the running system. This is useful when you need to recover a deleted configuration file or compare two versions of a service unit.
Here is how to mount a snapshot for inspection:
sudo snapper mount 42 # Mounts snapshot 42 read-only to /snapshots/42/snapshot
ls -la /snapshots/42/snapshot/etc/ # Browse the filesystem state at that exact moment
sudo snapper unmount 42 # Removes the mount point when you are finished
The mount point lives under /snapshots/. Each snapshot gets its own directory. The filesystem inside is completely static. You can copy files out of it, but you cannot modify them. Unmounting cleans up the directory structure automatically.
Mount snapshots before you delete anything. You cannot recover a file from a snapshot you cannot mount.
Rolling back from a live terminal
Rolling back is the core operation. You can perform a rollback from a running terminal if the kernel and init system are still functional. If the system fails to boot past the kernel, you will use the GRUB menu instead.
Here is how to roll back from a live terminal:
sudo snapper rollback 42 # Unmounts current root, mounts snapshot 42 as new root
sudo reboot # Restarts the system into the restored state
sudo snapper list # Confirms the current root now points to the restored snapshot
The rollback command does not delete your current state. It swaps the active subvolume pointer and schedules a reboot. Your current root becomes a new snapshot automatically. This preserves your ability to step forward again if the rollback was a mistake.
The command modifies the bootloader configuration to make the restored snapshot the default boot target. On the next boot, the system loads the exact kernel and initramfs from the restored state. Your user data in @home remains untouched unless you explicitly rolled back that subvolume as well.
Reboot before you debug. Half the time the symptom is gone.
Recovering through the GRUB menu
If the system drops to an emergency shell or fails to start the display manager, you can still recover. Reboot the machine and hold the Shift key during startup to reveal the GRUB menu. Select the entry labeled with your target snapshot ID. The bootloader will mount that snapshot as the root filesystem instead of the default subvolume.
The GRUB menu entries are generated automatically by grub2-mkconfig during each Snapper operation. Each snapshot gets a dedicated menu item under the Advanced options for Fedora submenu. The entry name includes the snapshot ID and timestamp.
Here is how to verify the GRUB configuration after a rollback:
sudo grep -A 2 "menuentry.*snapshot" /boot/grub2/grub.cfg # Locates the snapshot boot entries
sudo grub2-mkconfig -o /boot/grub2/grub.cfg # Regenerates the menu if entries are missing
sudo systemctl status grub-boot-indeterminate.service # Checks if the bootloader state is locked
Once you are logged in from the GRUB snapshot entry, run sudo snapper rollback <ID> to make the change permanent across future boots. The command updates the default boot target and removes the temporary override.
Trust the package manager. Manual file edits drift, snapshots stay.
Tuning retention and reclaiming space
Snapshots consume space as the live system diverges from them. Btrfs tracks shared blocks, but every unique file written after a snapshot is taken adds to the disk usage. Fedora includes a timer that runs snapper cleanup periodically. The cleanup process follows rules defined in the configuration file.
The configuration lives in /etc/snapper/configs/root. Never edit files in /usr/lib/snapper/configs/. Those are package defaults. Your changes in /etc/ override them and survive package updates.
Here is how to adjust the retention limits:
# /etc/snapper/configs/root
NUMBER_LIMIT="5" # Keeps only the last 5 non-timeline snapshots
NUMBER_LIMIT_IMPORTANT="5" # Keeps snapshots marked as important
TIMELINE_CREATE="yes" # Enables automatic timeline snapshots
TIMELINE_LIMIT_HOURLY="2" # Keeps 2 hourly snapshots
TIMELINE_LIMIT_DAILY="7" # Keeps 7 daily snapshots
TIMELINE_LIMIT_WEEKLY="0" # Disables weekly snapshots
TIMELINE_LIMIT_MONTHLY="0" # Disables monthly snapshots
TIMELINE_LIMIT_YEARLY="0" # Disables yearly snapshots
After editing the file, run sudo systemctl reload snapper.timer to apply the changes. The next cleanup cycle will enforce the new limits. You can also force an immediate cleanup with sudo snapper cleanup. The command evaluates every snapshot against the rules and deletes anything that exceeds the thresholds.
Check disk usage with btrfs filesystem usage /. The Data, single and System, single rows show actual allocated space. The Unallocated row shows free space. If your disk is filling up, lower the NUMBER_LIMIT values or reduce the timeline limits. Btrfs will reclaim the space automatically once the snapshots are deleted.
Run journalctl -xeu snapper.timer after a cleanup cycle. Read the actual log lines before guessing why space was not freed.
Common pitfalls and error messages
Snapper depends on correct subvolume mapping and proper SELinux contexts. Misconfigurations usually surface as mount failures or permission denials.
You will see this error if the subvolume path in the config does not match your actual layout:
snapper: error: Subvolume '@' not found.
Verify your Btrfs layout with sudo btrfs subvolume list /. The output shows the actual mount points and subvolume names. Update the SUBVOLUME line in /etc/snapper/configs/root to match.
You will see this error if SELinux blocks the mount operation:
mount: /snapshots/42/snapshot: permission denied.
Run journalctl -t setroubleshoot | tail -n 5 to read the denial summary. Snapper requires the snapper_t domain to access the subvolumes. Restore the default contexts with sudo restorecon -Rv /snapshots/. Do not disable SELinux to work around this. Fix the context labels instead.
You will see this error if you try to roll back while a dnf transaction is still running:
snapper: error: Cannot rollback while a transaction is running.
Wait for the package manager to finish. Check the status with sudo systemctl status dnf-makecache.timer or simply wait for the terminal prompt to return. Rolling back during an active transaction corrupts the package database.
You will see this warning if your disk is critically full:
snapper: warning: Not enough space to create snapshot.
Delete old snapshots manually with sudo snapper delete <ID> or lower the retention limits. Btrfs cannot allocate new metadata blocks when the filesystem is over 90 percent full.
Snapshot the system before the upgrade. Future-you will thank you.
When to use Snapper versus other tools
Use Snapper when you want automatic, transaction-aware snapshots tied to dnf operations. Use Timeshift when you are running a different Linux distribution that relies on ext4 and need a simpler GUI tool. Use bare Btrfs subvolumes and btrfs subvolume snapshot when you want full control over the snapshot naming and placement without systemd timers. Use LVM snapshots when your system uses traditional block devices and cannot migrate to Btrfs. Stay on the default Fedora Snapper configuration if you only need protection against broken updates and accidental file deletions.