ext4, XFS and Btrfs are the three general-purpose filesystems you will meet on Linux servers. ext4 is the default on Ubuntu and Debian, XFS on Red Hat Enterprise Linux and its rebuilds, and Btrfs on Fedora Workstation and openSUSE. This guide compares them feature by feature, lets you try each one safely on loop devices in Ubuntu 24.04, and ends with clear recommendations for common server workloads.
Prerequisites
To run the examples you need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with a non-root user that has
sudoprivileges. - About 12 GB of free disk space for three test images. The examples use loop devices (files that behave like disks), so no real disk is touched.
Install the user-space tools for XFS and Btrfs. The ext4 tools (e2fsprogs) are already installed:
sudo apt update
sudo apt install xfsprogs btrfs-progs
Comparison at a glance
| Feature | ext4 | XFS | Btrfs |
|---|---|---|---|
| Default on | Ubuntu, Debian | RHEL, Rocky, AlmaLinux | Fedora Workstation, openSUSE |
| Grow online | Yes | Yes | Yes |
| Shrink | Yes, unmounted only | No | Yes, online |
| Metadata checksums | Yes | Yes | Yes |
| Data checksums | No | No | Yes |
| Native snapshots | No (use LVM) | No (use LVM) | Yes |
| Transparent compression | No | No | Yes (zstd, lzo, zlib) |
| Built-in multi-disk / RAID | No | No | Yes (RAID 1 and 10 are stable; avoid RAID 5/6) |
Reflink copies (cp --reflink) | No | Yes | Yes |
| Repair tool | e2fsck | xfs_repair | btrfs check (use with care) |
| Maturity | Very high | Very high | High, some features still maturing |
In short: ext4 is the simple, predictable choice; XFS scales best for large files and parallel I/O but cannot shrink; Btrfs adds snapshots, checksums for data and compression at the cost of more complexity.
Setting up test devices
Create three 4 GB image files and attach each one to a loop device. losetup --show prints the device it chose:
sudo truncate -s 4G /var/tmp/ext4.img /var/tmp/xfs.img /var/tmp/btrfs.img
sudo losetup --find --show /var/tmp/ext4.img
sudo losetup --find --show /var/tmp/xfs.img
sudo losetup --find --show /var/tmp/btrfs.img
/dev/loop3
/dev/loop4
/dev/loop5
Your numbers may differ, because snap packages already use some loop devices. The next sections use /dev/loop3, /dev/loop4 and /dev/loop5; replace them with the ones printed on your system.
ext4: the reliable default
ext4 descends from ext2 and ext3 and has been the default Linux filesystem for more than a decade. It journals metadata, has fast fsck times, and every rescue tool and distribution knows it. Its limits (1 EiB per filesystem, 16 TiB per file with 4 KiB blocks) are far beyond what a single server needs.
Create and mount an ext4 filesystem:
sudo mkfs.ext4 -L test-ext4 /dev/loop3
sudo mkdir -p /mnt/ext4
sudo mount /dev/loop3 /mnt/ext4
By default ext4 reserves 5% of the blocks for root, so that system services can still write when users fill the disk. On a large data disk that is a lot of wasted space. Check and lower it to 1%:
sudo tune2fs -l /dev/loop3 | grep 'Reserved block count'
sudo tune2fs -m 1 /dev/loop3
Reserved block count: 52428
tune2fs 1.47.0 (5-Feb-2023)
Setting reserved blocks percentage to 1% (10485 blocks)
ext4 can also shrink, but only while unmounted and after a filesystem check. This shrinks the filesystem to 3 GB (the underlying device keeps its size):
sudo umount /mnt/ext4
sudo e2fsck -f /dev/loop3
sudo resize2fs /dev/loop3 3G
Resizing the filesystem on /dev/loop3 to 786432 (4k) blocks.
The filesystem on /dev/loop3 is now 786432 (4k) blocks long.
Choose ext4 when: you want the default that works everywhere, the root filesystem of a VPS, general web and application servers, small to medium databases, or any disk you might need to shrink later.
XFS: built for large files and parallel I/O
XFS was designed by SGI for large storage systems. It splits the filesystem into allocation groups that can be written in parallel, which makes it very good with large files, many concurrent writers and big arrays. Red Hat uses it as the default for that reason.
Create and mount an XFS filesystem:
sudo mkfs.xfs -L test-xfs /dev/loop4
sudo mkdir -p /mnt/xfs
sudo mount /dev/loop4 /mnt/xfs
Inspect its geometry. agcount is the number of allocation groups and reflink=1 means copy-on-write file clones are enabled:
sudo xfs_info /mnt/xfs
meta-data=/dev/loop4 isize=512 agcount=4, agsize=262144 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=1
= reflink=1 bigtime=1 inobtcount=1 nrext64=0
data = bsize=4096 blocks=1048576, imaxpct=25
XFS grows online, and it is always grown by mount point. Enlarge the image to 6 GB, tell the loop device about the new size, then grow the filesystem:
sudo truncate -s 6G /var/tmp/xfs.img
sudo losetup -c /dev/loop4
sudo xfs_growfs /mnt/xfs
df -h /mnt/xfs
Filesystem Size Used Avail Use% Mounted on
/dev/loop4 6.0G 150M 5.8G 3% /mnt/xfs
The important limit: XFS cannot be shrunk. The only way to make an XFS filesystem smaller is to back it up, recreate it and restore the data, so do not give an XFS volume more space than you are sure it will keep.
Choose XFS when: you store large files (media, backups, logs, object storage), run high-throughput databases on dedicated volumes, have large multi-disk arrays, or run RHEL-family systems where it is the tested default.
Btrfs: snapshots, checksums and compression
Btrfs is a copy-on-write filesystem: it never overwrites data in place, which makes cheap snapshots possible. It checksums both data and metadata, so it detects silent corruption, and it can compress data transparently.
Create and mount a Btrfs filesystem with zstd compression:
sudo mkfs.btrfs -L test-btrfs /dev/loop5
sudo mkdir -p /mnt/btrfs
sudo mount -o compress=zstd /dev/loop5 /mnt/btrfs
Btrfs organizes data in subvolumes, which behave like independent directory trees that can be snapshotted and mounted separately. Create one and put a file in it:
sudo btrfs subvolume create /mnt/btrfs/@data
echo "version 1" | sudo tee /mnt/btrfs/@data/config.txt
Take a read-only snapshot. It is instant and uses no extra space until the data changes:
sudo btrfs subvolume snapshot -r /mnt/btrfs/@data /mnt/btrfs/@data-snap1
echo "version 2" | sudo tee /mnt/btrfs/@data/config.txt
cat /mnt/btrfs/@data-snap1/config.txt
version 1
The snapshot still holds the old content. List the subvolumes:
sudo btrfs subvolume list /mnt/btrfs
ID 256 gen 8 top level 5 path @data
ID 257 gen 9 top level 5 path @data-snap1
Because Btrfs allocates space in chunks for data and metadata separately, df can be misleading. Use Btrfs's own report:
sudo btrfs filesystem usage /mnt/btrfs
Run a scrub to read every block and verify it against its checksum. On a multi-disk Btrfs with RAID 1, scrub also repairs bad copies from the good one:
sudo btrfs scrub start -B /mnt/btrfs
Scrub started: Thu Sep 24 10:20:11 2026
Status: finished
Duration: 0:00:00
Total to scrub: 320.00KiB
Error summary: no errors found
Keep these limitations in mind:
- Copy-on-write fragments files that are rewritten in place, such as database files and VM disk images. For those, create the directory empty and disable CoW on it with
sudo chattr +C /path/to/dir; files created inside then skip CoW, which also disables their checksums and compression. - The built-in RAID 5 and RAID 6 modes are still not recommended for production. Use RAID 1 or RAID 10, or put Btrfs on top of
mdadm. - When the metadata space fills up, writes can fail with
No space left on deviceeven thoughdfshows free space. A filtered balance usually frees it:sudo btrfs balance start -dusage=50 /mnt/btrfs.
Choose Btrfs when: you want snapshots before upgrades or for backups (btrfs send and receive), you store compressible data such as logs, text or source code, you want data checksums on a workstation or small file server, or you run openSUSE or Fedora where it is well integrated.
Which one should you choose
For most cases the decision is short:
| Workload | Recommendation |
|---|---|
| Root filesystem of a VPS or general server | ext4, the Ubuntu and Debian default |
| MySQL, PostgreSQL on a dedicated volume | ext4 or XFS |
| Large files, backups, media, log archives | XFS |
| Big multi-disk arrays with high parallel I/O | XFS on mdadm or LVM |
| Frequent snapshots, rollback before upgrades | Btrfs, or ext4/XFS on LVM with snapshots |
| Compressible data, space-constrained disks | Btrfs with compress=zstd |
| Disks you may need to shrink later | ext4 or Btrfs, not XFS |
If you are unsure, use ext4. It is the most forgiving choice, and the tools to repair and resize it are always available. Pick XFS for scale and Btrfs for its features, not by default.
You can check which filesystem any mount uses with:
findmnt -no FSTYPE /
ext4
Cleaning up the test devices
Unmount the filesystems, detach the loop devices and remove the images:
sudo umount /mnt/ext4 /mnt/xfs /mnt/btrfs
sudo losetup -d /dev/loop3 /dev/loop4 /dev/loop5
sudo rm /var/tmp/ext4.img /var/tmp/xfs.img /var/tmp/btrfs.img
/mnt/ext4 was already unmounted during the shrink test, so umount may report that it is not mounted; that is expected.
Conclusion
ext4 is the safe default, XFS scales best for large files and parallel workloads but cannot shrink, and Btrfs adds snapshots, data checksums and compression in exchange for more care around databases and multi-disk setups. As next steps, partition and format a real data disk with the filesystem you picked, add LVM underneath ext4 or XFS if you want flexible resizing and snapshots, and schedule regular checks: fstrim.timer for SSDs is already enabled on Ubuntu, and a monthly btrfs scrub is worthwhile on Btrfs.
