What is BTRFS
Because I am currently intensively dealing with BTRFS and doing some research to shed light on this topic for myself, here is a list of my findings, explanations, and instructions. If you have any comments on this, you can find me in the Fediverse (About page). Otherwise, as always, I hope that this article helps one or another person to gain more clarity on the topic as well. And … write more blog articles yourself!
BTRFS stands for B-Tree File System and is a modern copy-on-write file system that was originally developed in 2007 by Chris Mason at Oracle and added to the Linux kernel 2.6.29 in 2009. It is now supported by various distributions and companies, including Debian, SUSE, Red Hat, Fujitsu, and Intel.
The essential difference from classic file systems such as ext4 or NTFS is that BTRFS does not overwrite data. When a file is changed, BTRFS writes the new version to a different location while the old version is retained until it is no longer needed.
This gives rise to several features:
- Snapshots: Point-in-time captures of the file system that initially take up hardly any additional storage space.
- Data integrity: BTRFS calculates checksums for data and metadata. Errors caused by faulty RAM or aging storage media are detected and can be corrected if redundancy is available (e.g., RAID1).
- Subvolumes: The file system can be divided into logical parts, similar to partitions, but more flexible.
- Transparent compression: Data can be compressed on the fly (e.g., with zstd).
- Integrated RAID support for RAID 0, 1, 10, 5, and 6.
What Are Snapshots
A snapshot is a point-in-time capture of the file system. The current state of a folder is recorded and can be restored later.
Thanks to copy-on-write, a fresh snapshot initially takes up hardly any additional storage space. It points to the same data blocks as the original. Only when changes are made do new blocks come into existence while the old version is retained in the snapshot. The additional space consumption therefore corresponds to the difference between the original and the snapshot.
This gives rise to typical use cases:
- Before system updates: Create a snapshot, perform the update, roll back if there are problems.
- Automatic backups: Tools such as Snapper can create snapshots at fixed intervals and automatically delete old ones.
- Experiments: Changes can be tested and, if necessary, completely undone.
Important: A snapshot is not a backup. In the event of a hardware failure, both the original and the snapshot are lost. Snapshots protect against logical errors such as faulty updates or accidental deletion, not against hardware failures. For real backups, snapshots are transferred to another medium using
btrfs sendandbtrfs receive.
Notes
Snapshots are not a substitute for backups. A few points should be noted:
- Space consumption: Old snapshots can take up a lot of space over time because they hold the differences from later changes. Automatic cleanup is therefore sensible.
- Performance: With very large amounts of data or databases, copy-on-write can slow things down. For such cases, files or subvolumes can be marked with the
nodatacowattribute. - Kernel and bootloader: If
/bootis included in the snapshot, a rollback can become problematic if the kernel and modules no longer match. Many distributions therefore exclude/bootor handle the kernel separately.
Snapshots with btrfs “tool”
Snapshots can be created and managed entirely without additional tools such as Snapper or Timeshift. The necessary commands are part of btrfs-progs, which is present on every system with Btrfs support.
Creating a Snapshot
A snapshot is created with btrfs subvolume snapshot. The command requires a source subvolume and a target directory for the snapshot.
Read-only snapshot (recommended for backups):
sudo btrfs subvolume snapshot -r /home /snapshots/home/home_snapshot_$(date +%Y%m%d_%H%M%S)
The -r option creates a read-only snapshot. This cannot be changed accidentally and is suitable for later transfer with btrfs send.
Writable snapshot (for tests or clones):
sudo btrfs subvolume snapshot /home /snapshots/home/home_snapshot_ro
Without -r, a writable snapshot is created, which can be used like a complete copy of the file system.
Important: Snapshots can only be created from subvolumes, not from normal directories. If the source is not a subvolume, Btrfs returns an error. The target directory /snapshots/home/ must be located on its own subvolume or outside the source subvolume so that no recursive structure is created.
Listing Snapshots
All subvolumes and snapshots can be displayed with the following command:
sudo btrfs subvolume list /
The output shows, among other things, the ID, the parent ID, and the path of each subvolume. With the -s option, only snapshots are listed; with -r, only read-only ones.
A typical output of sudo btrfs subvolume list / looks like this:
ID 256 gen 12345 top level 5 path @
ID 257 gen 12340 top level 5 path @home
ID 258 gen 12200 top level 5 path @snapshots
ID 259 gen 12050 top level 5 path snapshots/home/home_snapshot_2026-03-14
ID 260 gen 11980 top level 5 path snapshots/home/home_snapshot_ro
The columns in detail:
- ID: The unique number of the subvolume. This is used internally by Btrfs and is not to be confused with Snapper’s snapshot number.
- gen: The generation, i.e., a counter that is incremented with every transaction in the file system. A higher value means that the subvolume was last changed later.
- top level: The ID of the parent subvolume. The value
5stands for the top-level subvolume, i.e., the root of the Btrfs file system. - path: The path of the subvolume relative to the top-level subvolume. This shows where the subvolume is located in the tree.
In this example, one can see:
@is the root subvolume (ID 256).@homeis a separate subvolume for/home(ID 257).@snapshotsis its own subvolume (ID 258).snapshots/home/home_snapshot_2026-03-14andsnapshots/home/home_snapshot_roare the snapshots that were created under the path/snapshots/home/.
Note: The output shows the paths relative to the top-level subvolume, not relative to the mounted root. If /snapshots is mounted as a separate subvolume, the snapshot path appears accordingly under snapshots/home/.... If /snapshots is not mounted separately, the snapshots are located within the root subvolume and appear as @/snapshots/home/....
With the -s option, only snapshots are displayed:
sudo btrfs subvolume list -s /
With the -r option, only read-only subvolumes:
sudo btrfs subvolume list -r /
With the -t option, the type of subvolume (snapshot or subvolume) is also output:
sudo btrfs subvolume list -t /
Deleting a Snapshot
A snapshot is not removed with rm -rf, but with:
sudo btrfs subvolume delete /snapshots/home/home_snapshot_ro
The corresponding directory is removed immediately, but the actual data blocks are deleted in the background. The command returns immediately without waiting for the data deletion to complete.
If you want to wait until the deletion is fully complete:
sudo btrfs subvolume sync /snapshots/home
Rolling Back a Snapshot
To roll back to a snapshot, the current subvolume is moved and the snapshot is copied into its place:
## Rename the current subvolume as a backup
sudo mv /mnt/btrfs_root/@home /mnt/btrfs_root/@home_backup_$(date +%Y%m%d)
## Copy the snapshot as the new subvolume
sudo btrfs subvolume snapshot \
/snapshots/home/home_snapshot_20260301 \
/mnt/btrfs_root/@home
After mounting again, the restored state is available. The old state remains under @home_backup_... until it is manually deleted.
Backing Up Snapshots with send/receive
For real backups outside the system, btrfs send and btrfs receive are used. Both operations require read-only snapshots.
Initial backup:
sudo btrfs send /snapshots/home/home_snapshot_ro | btrfs receive /backupvol
Incremental backup (only changes since the last snapshot):
sudo btrfs send -p /snapshots/home/home_snapshot_ro /snapshots/home/home_snapshot_20260314 | btrfs receive /backupvol
The -p option specifies the previous snapshot as the parent. Only the differences between the two snapshots are transferred.
Creating, Configuring, and Using @snapshots
The storage location for snapshots is defined in the Btrfs subvolume layout and in /etc/fstab, not in Snapper’s configuration file. In Snapper’s configuration, SUBVOLUME merely specifies for which directory snapshots should be created (e.g., /). Whether the snapshots remain in the same subvolume or are relocated is decided by the configuration via the Btrfs subvolume structure and the mount entries in /etc/fstab.
In the Snapper configuration, reference is made to the @snapshots definitions in /etc/fstab.
Btrfs Option List
subvol=NAME / subvolid=ID
Specifies which subvolume appears under the mount point. subvol=@ mounts the subvolume @ as root. Without this option, the default subvolume is used.
compress=TYPE / compress-force=TYPE
Enables transparent compression. Possible types: zlib (default), lzo, zstd. compress-force also compresses files that do not compress well. Important: Compression is incompatible with nodatacow – when nodatacow is active, compress is ignored.
nodatacow
Disables copy-on-write for the entire file system. Important: This option affects the whole file system, not just one subvolume. Only the options of the first mounted subvolume are effective. nodatacow implies nodatasum – checksums are no longer calculated.
nodatasum
Disables checksums for data. Is automatically enabled with nodatacow.
autodefrag / noautodefrag
Enables automatic defragmentation for small, random write operations. Not suitable for databases or VM images. Warning: Can destroy extent sharing with snapshots/reflinks and greatly increase space consumption.
commit=SECONDS
Sets the interval for periodic commits. Default: 30 seconds. Higher values delay writing to persistent storage – in the event of a system crash, more data is lost.
ssd / nossd
Tells the file system that it is running on an SSD. Btrfs then optimizes block allocation. Often detected automatically on modern kernels.
discard / nodiscard / discard=async
discard enables synchronous TRIM on every deletion – can impair performance. discard=async (since kernel 5.6) collects freed blocks and performs TRIM asynchronously – the preferred method. Alternatively: nodiscard and periodic fstrim.
space_cache / space_cache=v1 / space_cache=v2 / nospace_cache
Controls the free-space cache. v2 (default since kernel 4.5) is significantly more performant for large file systems. nospace_cache disables the cache.
acl / noacl
Enables/disables POSIX ACLs. Default: acl.
barrier / nobarrier
barrier (default) ensures that I/O operations go through the device cache and are persistently stored. nobarrier can increase performance but will definitely lead to data loss in the event of a power failure.
degraded
Allows mounting with missing devices (e.g., with RAID). A read-write mount can fail if too many devices are missing.
skip_balance
Skips the automatic resumption of an interrupted balance operation.
Options for Special Use Cases
Swapfile on Btrfs A swapfile must meet the following conditions:
- Must be preallocated, no holes
- Must be NODATACOW (implies NODATASUM) - more on this in the next chapter
- No compression
- The containing subvolume must not be snapshotted while the swapfile is active
- Only a single device and a single data profile
Example for a swap subvolume in fstab:
UUID=... /swap btrfs subvol=@swap,nodatacow,noatime 0 0
/etc/fstab Practical Example
Here is an example fstab with the most important options.
## <file system> <mount point> <type> <options> <dump> <pass>
UUID=xxxxxxxx-xxxx-xxxx-xxxx / btrfs subvol=@,compress=zstd:3,noatime,ssd,discard=async,space_cache=v2 0 1
UUID=xxxxxxxx-xxxx-xxxx-xxxx /home btrfs subvol=@home,compress=zstd:3,noatime,ssd,discard=async,space_cache=v2 0 2
UUID=xxxxxxxx-xxxx-xxxx-xxxx /.snapshots btrfs subvol=@snapshots,noatime,ssd,space_cache=v2 0 0
Critical Limitations Regarding nodatacow and compress
Options apply to the entire file system:
nodatacow,nodatasum, andcompresscannot be controlled per subvolume via mount options. Only the options of the first mounted subvolume count.chattr +C - To disable copy-on-write only for specific data without affecting the entire file system, setting the C attribute at the file or directory level is the right approach
nodatacow+compressare mutually exclusive: Ifnodatacowis set, compression is automatically disabled.nodatacowand snapshots: Snapshots still work, but on the first write after a snapshot, CoW is forced in order to preserve the old blocks. The advantage ofnodatacowis thus limited.nodatacowremoves data integrity: Withoutnodatasumthere are no checksums. On multi-disk systems (RAID1), after a crash it cannot be determined which copy is correct – with about a 50% probability the corrupted copy is read.Avoid
autodefragwith snapshots: Auto-defragmentation breaks reflink and snapshot connections and can significantly increase space consumption.
chattr +C instead of nodatacow
To disable copy-on-write only for specific data (e.g., VM images or databases) without affecting the entire file system, setting the C attribute at the file or directory level is the right approach
## Create a new, empty directory (or rename an existing one)
sudo mkdir /var/lib/libvirt/images_nocow
sudo chattr +C /var/lib/libvirt/images_nocow
All newly created files in this directory inherit the NOCOW attribute
For already existing files, a workaround is necessary:
# Rename the directory, create a new one, set the attribute, copy the data back
sudo mv /var/lib/libvirt/images /var/lib/libvirt/images_old
sudo mkdir /var/lib/libvirt/images
sudo chattr +C /var/lib/libvirt/images
sudo cp -a --reflink=never /var/lib/libvirt/images_old/. /var/lib/libvirt/images/
sudo rm -rf /var/lib/libvirt/images_old
The parameter --reflink=never is crucial, because otherwise cp creates a CoW copy (reflink) by default, which does not inherit the attribute.
Important Limitation: Snapshots
Even with chattr +C there is a limitation: When a snapshot is created, it partially breaks the NOCOW property. On the first write to a file after a snapshot, CoW is forced in order to preserve the old blocks for the snapshot. After that, NOCOW applies again until the next snapshot is created.
For VM images or databases that should be excluded from snapshots, it is therefore advisable to place them on a separate partition with nodatacow or possibly another file system.
The Standard Layout in Manjaro
During automatic partitioning, Manjaro creates a large Btrfs partition with several subvolumes. The naming convention traditionally begins with an @ character.
Although the exact names may vary depending on the installer version, the typical layout corresponds to what is described as a convention in the Manjaro wiki:
@: The root file system (/).@home: The directory for user data (/home).@snapshots(optional): In the wiki, this subvolume is mentioned as an example of a possible snapshot storage location, but it is not part of the standard installation.
This means: In a standard Manjaro installation, all snapshots that you create, for example with Timeshift or Snapper, are by default located within the @ subvolume under /.snapshots. A separate subvolume for snapshots is not created.
The Standard Layout in TUXEDO OS (Debian-based)
TUXEDO OS uses Btrfs and Snapper by default to create automatic snapshots before and after package updates.
TUXEDO states that during installation six subvolumes are created, which act as separate namespaces within a Btrfs partition. However, the exact names of these six subvolumes are not explicitly listed in the official announcement.
What is known from the official TUXEDO documents:
- Snapper is preconfigured and automatically creates snapshots.
- A graphical tool called Btrfs Assistant is installed to manage subvolumes and snapshots.
- The first snapshot is created during the first boot process and is referred to as the “Factory Image”.
Automation Without External Tools
For regular snapshots, an entry in the crontab is sufficient. A simple shell script creates a timestamped snapshot:
#!/bin/bash
NOW=$(date +"%Y-%m-%d_%H:%M:%S")
mkdir -p /snapshots/home
sudo btrfs subvolume snapshot -r /home "/snapshots/home/home_snapshot_${NOW}"
This script can be executed at fixed intervals via cron or systemd-timer.
- Snapshots are not backups. They reside on the same file system. In the event of a hardware failure, both the original and the snapshot are lost. For real backups, snapshots must be transferred to another medium, for example with
btrfs send.- Delete old snapshots regularly. Snapshots take up storage space, even if they initially require hardly any additional space. Over time, differences accumulate. Regular cleanup is necessary.
- Pay attention to nested subvolumes. If a subvolume contains another subvolume, this is not backed up with the snapshot. The directory entry remains empty. For complete backups, nested subvolumes must be handled separately.
Tool: Snapper - Snapshot Management
Snapper is a tool for managing file system snapshots under Linux. It was originally developed by SUSE and is now available in many distributions.
Snapper automates the creation, management, and cleanup of BTRFS snapshots. It creates snapshots manually, or also automatically during package updates, or also scheduled.
List
With snapper it is more convenient. List snapshots with
snapper list
A typical output of snapper list looks like this:
# | Type | Pre # | Date | User | Cleanup | Description
---+-------+-------+------------------------------+----------+-------------+---------------------------
0 | single| | | root | | current
1 | single| | 2026-09-20 08:15:03 +0200 | root | timeline | timeline
2 | pre | | 2026-09-22 19:40:11 +0200 | root | number | zypp(packagekitd)
3 | post | 2 | 2026-09-22 19:41:57 +0200 | root | number | zypp(packagekitd)
4 | single| | 2026-09-23 03:00:01 +0200 | root | timeline | timeline
5 | pre | | 2026-09-25 14:02:33 +0200 | root | number | zypp(zypper)
6 | post | 5 | 2026-09-25 14:03:12 +0200 | root | number | zypp(zypper)
The columns in detail:
- #: The number of the snapshot. This is used for
snapper delete,snapper diff, orsnapper undochange. - Type:
singlefor standalone snapshots,preandpostfor pairs before and after a change. - Pre #: For a
postsnapshot, the number of the associatedpresnapshot. Forsingleandpre, the column remains empty. - Date: Time of creation.
- User: The user who triggered the snapshot (usually
root). - Cleanup: The cleanup strategy.
timelinefor scheduled snapshots,numberfor a fixed number,empty-pre-postfor orphaned pairs. - Description: Free text, for package operations e.g.,
zypp(zypper)orzypp(packagekitd).
This example also shows why pre/post pairs should be deleted together: Snapshots 5 and 6 belong together, as do 2 and 3. A snapper delete 5-6 removes the pair 5 and 6, a snapper delete 2-3 accordingly removes the pair 2 and 3.
Changes - diff
To see changes between two snapshots, snapper diff is used:
sudo snapper -c root diff 1..3
The output shows which files were added, deleted, or changed between the snapshots.
Deleting
When using snapper, deletion is done via:
sudo snapper -c root delete NUMBER
Here NUMBER is the number of the snapshot from snapper list. Automatically created pre/post pairs – for example before and after a package update – should always be deleted together, since they belong together. Snapper can do this with a single command:
sudo snapper -c root delete NUMBER1-NUMBER2
This removes both snapshots of the pair in one step.
Deletion Strategy
There are situations in which only the post snapshot is removed while the pre snapshot is retained. This makes sense, for example, when:
- The pre snapshot is to serve as a rollback point: Before an update, a
presnapshot is created. After the update, thepostsnapshot is normally only needed to document the changes. If you want to keep the rollback point but no longer the comparison basis, you delete only thepost. - Storage space becomes scarce: The
presnapshot marks the state before the change and is therefore the actually valuable one. Thepostsnapshot is often dispensable if the change was successful. - Snapper does not take effect with
numbercleanup: With thenumbercleanup strategy, Snapper prefers to delete entire pairs. If a single snapshot remains – for example because theprewas manually marked as worthy of protection – thepostmay have to be removed manually.
In practice, deleting only the post snapshot is more of an exception. It is customary to remove both together, because the pre snapshot without an associated post is considered orphaned during cleanup and is then automatically removed via the empty-pre-post strategy.
Rolling Back
Snapper offers two variants:
- Restore individual files: With
snapper undochange, changes between two snapshots are undone. The snapshots themselves are located under/.snapshots/NUMBER/snapshot/and can also be viewed directly. - Roll back the complete system: With
snapper rollback, the root subvolume is reset to an earlier snapshot. The prerequisite is that the desired snapshot has been booted into beforehand.
Restoring Individual Files
A snapshot behaves like a normal directory. When using Snapper, the snapshots are located under /.snapshots/NUMBER/snapshot/:
##### View snapshot contents
ls /.snapshots/5/snapshot/home/hoergen/
##### Copy an individual file back from the snapshot
sudo cp /.snapshots/5/snapshot/home/hoergen/.bashrc /home/hoergen/.bashrc
Alternatively, snapper undochange can be used to undo changes between two snapshots:
##### Undo changes between snapshot 5 (pre) and 6 (post)
sudo snapper -c root undochange 5..6
If only certain files are to be reset, they can be specified explicitly:
sudo snapper -c root undochange 5..6 /etc/fstab /etc/default/grub
Restoring the Complete System - Rollback
For completely rolling back the root file system, Snapper offers the command snapper rollback. The prerequisite is that the system has previously been booted into the desired snapshot. This is done via the boot menu that Snapper provides together with grub-btrfs. In the GRUB menu, an entry “BTRFS Snapshots” appears, from which any snapshot can be booted as the root subvolume.
After booting into the snapshot, the file system is mounted read-only. The rollback is then executed with the following command:
sudo snapper rollback
Optionally with a description:
sudo snapper rollback -d "Rollback after faulty update"
Snapper automatically creates a snapshot of the state before the rollback. After a restart, the system is at the state of the selected snapshot.
Important: snapper rollback only works for the root subvolume /. Other subvolumes such as /home are not rolled back.
Automation with Snapper
Manually creating snapshots is impractical in the long run. Snapper can automatically create timeline snapshots (e.g., hourly, daily, weekly) and delete old ones according to defined rules so that storage space does not run out.
Typical configuration under /etc/snapper/configs/root:
TIMELINE_CREATE="yes"
TIMELINE_CLEANUP="yes"
TIMELINE_LIMIT_HOURLY="6"
TIMELINE_LIMIT_DAILY="7"
TIMELINE_LIMIT_WEEKLY="4"
TIMELINE_LIMIT_MONTHLY="6"
TIMELINE_LIMIT_YEARLY="2"
FREE_LIMIT="0.2" # Leave at least 20% free
Activating the timers:
sudo systemctl enable --now snapper-timeline.timer
sudo systemctl enable --now snapper-cleanup.timer
This starts the automatic snapshots and the cleanup. Before a pacman -Syu or apt upgrade, a manual snapshot with a description can additionally be created:
sudo snapper -c root create --description "before the update"
After the update, snapper diff can be used to trace what changed. If necessary, a rollback can be performed.
Tool: grub-btrfs
grub-btrfs is a standalone tool that integrates the snapshots created by Snapper into the GRUB menu. After installation, an entry “BTRFS Snapshots” appears in the GRUB menu, from which any snapshot can be booted as the root subvolume. This is the prerequisite for rollback with snapper rollback.
Defragmentation: Options and Problems
The command btrfs filesystem defragment enables defragmentation of files and directory metadata during operation.
However, its use is associated with considerable limitations, especially when snapshots or reflink copies are used.
A reflink (short for “reference link”) is a special type of file copy that modern file systems such as Btrfs or XFS support. It uses the copy-on-write principle (CoW) to create a copy that initially takes up no additional storage space and is almost instantaneous.
Checking Fragmentation
Before performing defragmentation, it should be checked whether there is any relevant fragmentation at all. Btrfs does not report fragmentation automatically. The most reliable way is to measure the extents per file with filefrag and to observe the actual performance behavior.
There is no way to check an entire volume. It only works via
filefrag.
An entire Btrfs volume cannot be directly checked as a whole for its degree of fragmentation. There is no command that outputs a single number or percentage for the fragmentation of the entire file system.
The reason lies in the way Btrfs works. Fragmentation is a state that relates to individual files, not to the volume as a whole. A volume can contain thousands of files, some of which are heavily fragmented and others not at all. There is no meaningful single metric that would summarize this.
There is an indirect approach via storage consumption. If btrfs filesystem df shows a large discrepancy between Size (allocated space) and Used (actually occupied space), this indicates fragmented or orphaned extents. However, this is not a measurement of fragmentation, but a reaction to a suspected cause.
Measuring Fragmentation of Individual Files
filefrag is part of the e2fsprogs package and also works on Btrfs thanks to FIEMAP support. A file with a single extent is not fragmented; the more extents, the greater the fragmentation.
## Check fragmentation of a single file
filefrag /home/hoergen/.bashrc
Example output:
/home/hoergen/.bashrc: 3 extents found
Finding the Most Fragmented Files
For an overview of a directory, the output can be sorted. The number of extents is in the second column:
## Top 10 most fragmented files in the current directory
filefrag * | sort -nr -k 2 | head -10
sort -nr -k 2 thus sorts the lines by extent count, descending, with the highest number at the top.
-n: Numeric sorting. Without this option, sort would sort alphabetically, so that e.g., 10 would come before 2. With -n, the numeric value is interpreted.-r: Reverse order. Instead of ascending, sorting is descending, so the largest number comes first.-k 2: The sort key is the second column. By default, sort separates columns by spaces. In the output of filefrag, the second column is the number of extents.head -10outputs the first ten lines of the input by default. Since the input was previously sorted in descending order by extent count, the ten most fragmented files of the directory are shown here.
For the home directory accordingly:
## Top 10 most fragmented files in /home/hoergen
cd /home/hoergen
filefrag * | sort -nr -k 2 | head -10
For snapshots under /snapshots/home/..., a check is only worthwhile if there are actually files there that have been heavily modified. Since snapshots are generally read-only, their fragmentation no longer changes after creation.
Checking Typical Candidates
Certain directories tend to fragment more due to their usage pattern, and it may be worth considering the nodatacow mount option
## Check log directory
filefrag /var/log/journal/* | sort -nr -k 2 | head -10
## Check temporary directory
filefrag /tmp/* 2>/dev/null | sort -nr -k 2 | head -10
Performance as the Actual Indicator
The mere extent count says nothing about actual performance. Defragmentation only makes sense when a noticeable slowdown occurs. Examples:
- A database under
/home/hoergen/db/responds noticeably more slowly to queries. - A log file under
/var/log/slows down system startup.
Without such perceptible effects, on systems with snapshots the risks of defragmentation (loss of extent sharing, increased storage consumption) outweigh the benefits.
Limitation with Snapshots and Reflinks
Before a file is defragmented, it should be checked whether it is connected to a snapshot or a reflink copy. If that is the case, defragmentation breaks this connection and storage consumption increases. A targeted check of whether a file is shared with a snapshot is not directly possible with built-in tools. In practice, this means: Files that are contained in the usual snapshot paths such as /snapshots/home/... or /.snapshots/NUMBER/snapshot/ should not be defragmented.
Options for Defragmentation
Defragmentation can improve I/O performance by rewriting fragmented files into contiguous blocks. The command supports various options:
## Defragment a single file
sudo btrfs filesystem defragment /path/to/file
## Defragment a directory recursively
sudo btrfs filesystem defragment -r /path/to/directory
## With compression (zstd, zlib, or lzo)
sudo btrfs filesystem defragment -r -czstd /path
Important: Without the -r option, only metadata is defragmented, not the file contents. For complete file system defragmentation, -r is required.
Automatic Defragmentation (autodefrag)
The mount option autodefrag enables online defragmentation that automatically intervenes during small, random write operations. This option is suitable for desktop systems with normal usage, but is not recommended for large databases or VM images.
Activation in /etc/fstab:
UUID=... / btrfs defaults,autodefrag,compress=zstd 0 0
The Central Problem: Loss of Extent Sharing
The most critical disadvantage affects systems with snapshots or reflink copies. The official Btrfs documentation states clearly:
Defragmentation does not preserve extent sharing, e.g. files created by
cp --reflinkor existing on multiple snapshots. Due to that the data space consumption may increase.
What this concretely means:
When a file is defragmented that is currently shared by a snapshot or a reflink clone, the command breaks this sharing. It creates a new, private copy of the data for the defragmented file, while the snapshot continues to point to the old data blocks. Since both copies now exist separately, the storage space requirement for this data doubles.
An example: On a system with Snapper that creates hourly snapshots, defragmenting / can cause storage consumption to rise drastically because every defragmented file loses its connection to all existing snapshots.
Defrag - Conclusion
| Aspect | Assessment |
|---|---|
| Performance gain | Possible with fragmented files without snapshots |
| Storage space | Increases with snapshots/reflinks due to loss of extent sharing |
| Snapshot compatibility | Not given – snapshots lose their COW connection |
| Recommendation | Only for files without snapshot reference; avoid on Snapper systems |
For systems with Snapper or Timeshift, the following applies: Defragmentation should be avoided, unless it is applied specifically to files that are demonstrably not contained in snapshots. The storage space savings from snapshots outweigh the performance loss from fragmentation in most cases.
Defragmenting with Benefits & Risks - Backup
In order to be able to defragment after all, if it should really be necessary, a not really fully thought-out idea would be
- create a backup
- then delete all snapshots
- defragment
- create new snapshots
- create another backup
Conclusion & Best Practice
BTRFS with snapshots is a practical way to safeguard system changes. The manual commands are manageable, and with Snapper the process can be automated. For systems on which updates or experiments are frequently performed, this is a sensible setup. Switching from ext4 is not trivial, but is worth considering for a fresh installation or a second system.
Best Practice
- Standard layout with
@and@home(or as specified by the installer) - Use Snapper for automatic snapshots
- Manually create a snapshot before critical actions
- Install
grub-btrfsforsnapper rollback, because it integrates the snapshots into the GRUB menu. - Set fstab options sparingly
- Speed: Current performance tests show that BTRFS cannot yet keep up with XFS, ext4, and others, aka is sometimes extremely slower. If you need performance, you should currently use a different FS.
Caution
- Setting
nodatacowglobally autodefragin the fstab- Defragmentation on systems with snapshots
Sources
Official Btrfs Documentation
btrfs(5) Manpage – Mount options, compression, swapfile, limitations - https://manpages.debian.org/unstable/btrfs-progs/btrfs.5.en.html
btrfs(8) Manpage (Debian) – Toolbox for Btrfs management – https://manpages.debian.org/trixie/btrfs-progs/btrfs.8.en.html
btrfs(8) Manpage (Ubuntu) – Subvolume, device, and filesystem commands – https://manpages.ubuntu.com/manpages/noble/man8/btrfs.8.html
Btrfs readthedocs – Technical documentation, zoned mode, file attributes – https://btrfs.readthedocs.io/
Filesystem Performance - File System Performance Comparison Statistics 2026 https://commandlinux.com/statistics/file-system-performance-comparison-statistics-ext4-xfs-btrfs-zfs/
Snapper Documentation
- snapper-configs(5) Manpage – All configuration variables – https://manpages.opensuse.org/Tumbleweed/snapper/snapper-configs.5.en.html
- snapper(8) Manpage – Command reference, permissions, file paths – https://manpages.opensuse.org/Tumbleweed/snapper/snapper.8.en.html
- openSUSE Snapper Manpages – Overview of all Snapper manpages – https://en.opensuse.org/SDB:Snapper_Manpages
- SUSE Snapper Basic Concepts (PDF) – Snapshot types, default settings, storage space – https://documentation.suse.com/smart/systems-management/pdf/snapper-basic-concepts_en.pdf
Distributions and Practical Guides
- Manjaro Wiki – Btrfs – Subvolume concepts, snapshots, RAID, storage space – https://wiki.manjaro.org/index.php/Btrfs
- openSUSE Leap Reference (HTML) – Snapshot archiving, chattr +C, Snapper on LVM – https://doc.opensuse.org/documentation/leap/reference/html/book-reference/cha-snapper.html
- Oracle Linux Btrfs Docs – Send/receive workflow for backups – https://docs.oracle.com/en-us/iaas/oracle-linux/btrfs/ol-btrfs-creating-backups-and-using-the-btrfs-send-receive-feature.htm