Proxmox VEV · Storage FundamentalsFilesystem choices
Filesystems for VM disks: ext4, xfs, and ZFS on top
What you'll learn
- Compare ext4, xfs, and ZFS as filesystems for VM disk images
- Understand when each is the right choice for a Proxmox storage backend
- Recognise the operational trade-offs of each filesystem
- Pick a filesystem that matches your workload and recovery story
Prerequisites
Verified against Proxmox VE 9.2.4 · Proxmox Backup Server 4.2.5 · Ceph Squid / Tentacle · Debian 13 (Trixie) · Linux kernel 7.0 (PVE 9.2 default) · 2026-08-07
Filesystems for VM disks: ext4, xfs, and ZFS
Proxmox supports several filesystems underneath the qcow2 / raw abstraction. The right choice depends on your workload, your recovery story, and your willingness to operate a more complex stack.
The three options in practice
| Filesystem | CoW | Snapshots | Scrub | Send/receive | Used by default |
|---|---|---|---|---|---|
| ext4 | No | No | No | No | local (dir storage) |
| xfs | No | No (reflink since 6.10) | No | No | rarely on PVE |
| ZFS | Yes | Yes (cheap) | Yes | Yes | local-zfs |
The “used by default” column is the strongest signal: PVE ships with
both local (ext4 on a directory on the installer disk) and
local-zfs (ZFS pool on dedicated disks). xfs is supported but not
the default for either.
ext4 — the simple default
ext4 is a mature journaling filesystem with two-decade-old production history. It is what PVE puts on its installer disk by default when you don’t choose ZFS.
Strengths:
- Stable, predictable, well-understood. Every Linux admin has recovered an ext4 partition at 3am.
- Low overhead — no CoW, no checksums, no snapshots, no background scrub. The filesystem is essentially a fast allocator on top of the block device.
- No memory cost for caching (other than the page cache).
fsckrecovery is fast on small filesystems.
Weaknesses:
- No snapshots. To take a backup of a running VM on ext4, you must
pause it (
qm suspend 100) or useqemu-guest-agentto filesystem-freeze it. A “snapshot” is just a copy of the qcow2 file, and is only consistent if the guest cooperates. - No checksums. Silent corruption (bit rot) propagates from the disk up to the VM. ext4 trusts the storage layer to deliver correct blocks.
- No send/receive. Replication between hosts is a copy or rsync of the qcow2 file.
Right choice for: small / dev clusters, NFS shares used as
local storage, environments where you want the simplest possible
stack and you’re willing to accept some operational limitations.
xfs — the alternative journaling filesystem
xfs is also a mature journaling filesystem with excellent performance characteristics on large filesystems. Red Hat Enterprise Linux uses xfs by default, which is why some shops standardize on it.
Strengths:
- Excellent performance on large filesystems (multi-TB).
- Robust against unclean shutdowns.
- Online defragmentation and expansion.
- Reflink snapshots since Linux 6.10 — not yet exposed by PVE but coming.
Weaknesses:
- Same snapshot limitations as ext4 from PVE’s perspective.
- Less common in PVE environments, so less community knowledge.
- Recovery tools (
xfs_repair) require unmount and are slower than ext4’sfsck.
Right choice for: very large storage pools where ext4’s scaling limits become a concern, RHEL-skill-set shops.
ZFS — the production-grade choice
ZFS brings copy-on-write, snapshots, scrubs, checksums, and send/receive. It is the recommended filesystem for any production PVE cluster.
Strengths:
- Cheap snapshots — a snapshot is a property of the dataset, takes almost no space, and is instantaneous regardless of dataset size.
- Block-level checksums — every block is checksummed, and ZFS will detect and heal silent corruption from a redundant copy.
- Send/receive — replication between hosts is built in.
zfs send | zfs recvstreams the deltas of a snapshot. - Scrub — a periodic background scrub verifies every block’s checksum and rebuilds from redundancy where needed. Catch silent corruption before it reaches your VM.
- ARC, L2ARC, ZIL — tunable caching layers for read-heavy and write-heavy workloads.
Weaknesses:
- More memory — ARC consumes RAM. Rule of thumb: 1 GB per TB of storage, plus working set. On a 64 GB host with 8 TB of fast SSDs, ARC can take 8 GB.
- More complex — vdevs, ashift, recordsize, compression ratio, dedup. Each has trade-offs.
- Hardware RAID is incompatible — ZFS wants direct access to disks to manage redundancy itself. A hardware RAID controller hides individual disk failures from ZFS, defeating its self-healing model.
- No production-grade dedup. The dedup table is in-memory; with large working sets it overflows to disk and tanks performance. Use compression instead.
Right choice for: any production cluster, especially with redundant disks (mirror, RAIDZ), shared storage scenarios, and wherever backups and replication matter.
When the choice is made for you
Some workloads force one or the other:
- Ceph OSD backing — must be a raw block device. The filesystem above doesn’t matter; OSD manages its own btrfs / bluestore. ext4, xfs, or ZFS all work as the host filesystem on top of which OSDs run.
- ZFS-over-ZFS — running ZFS on top of a ZFS pool (e.g., ZFS volume exported as iSCSI to another PVE host running ZFS) is fine but adds overhead. Don’t do it unless you have a specific reason.
- NFS / CIFS share — the filesystem on the NFS server is invisible to PVE. PVE sees a flat directory of files. Choose whatever the NFS server runs.
- Hardware RAID controller in JBOD mode — the controller passes individual disks through. ZFS sees them as separate devices. This is fine and recommended.
Practical recommendations
For a typical production PVE cluster of 3 nodes with local storage:
- The boot disk: ext4 is fine. It’s a small filesystem that mostly holds the OS and PVE packages. ZFS boot is also fine but adds complexity for a small win.
- The VM storage pool: ZFS mirror on dedicated SSDs. Use
zfs create -o recordsize=64K -o compression=lz4 tank/vm-storage. 64K recordsize matches ZFS’s default volblocksize, which matches VM I/O patterns. - The PBS storage pool: ZFS mirror on dedicated HDDs. Recordsize doesn’t matter for chunk storage; PBS writes ~4 MB chunks sequentially. ARC caching helps for repeat reads of the same backup.
- The NAS / cold storage: ext4 on a large disk. Cheap, simple, effective.
CLI walkthrough
Inspect what filesystems you’re using:
df -hT | grep -v tmpfs
lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT
zpool list
zpool status -v
For a new ZFS pool for VM storage:
# Identify the disks (replace with your actual device IDs)
ls -la /dev/disk/by-id/ | grep -v part
# Create a mirror pool
zpool create -f -o ashift=12 tank mirror \
/dev/disk/by-id/ata-Samsung_SSD_870_EVO_1TB_S6PXNG0R200001 \
/dev/disk/by-id/ata-Samsung_SSD_870_EVO_1TB_S6PXNG0R200002
# Create the dataset with VM-tuned properties
zfs create -o recordsize=64K \
-o compression=lz4 \
-o atime=off \
-o primarycache=all \
tank/vm-storage
# Add it to PVE
pvesm add zfspool vm-storage --pool tank/vm-storage --content images,rootdir
Verify the pool is healthy:
zpool status tank
# Expected: state ONLINE, no errors, scrub completed recently
Schedule a weekly scrub:
# Modern PVE: this is set via systemd timer
systemctl enable --now zfs-scrub-weekly@tank.timer
# Or via the legacy cron
( crontab -l 2>/dev/null | grep -v 'zpool scrub' ; \
echo '0 3 * * 0 zpool scrub tank' ) | crontab -
Production considerations
- Different filesystems on the same host are fine. ext4 on the boot disk, ZFS for the VM pool, NFS mounted for cold storage — no conflict.
- Snapshot retention on ZFS — snapshots accumulate until you
prune them.
zfs list -t snapshotshows the count. Usepvesmretention policies orzfs-auto-snapshotto bound growth. - Compression —
lz4is essentially free on modern CPUs and gives 1.2x–1.5x compression on VM workloads. Always enable. - Recordsize — keep at 64K unless you have a specific reason. 128K helps sequential workloads (large databases), 16K helps small-file workloads (mail servers). The default is wrong for VMs.
Common mistakes
- Running ZFS on top of hardware RAID — defeats ZFS’s self-healing. Use the controller in JBOD / IT mode.
- Enabling dedup on production — the memory cost is enormous. Use compression instead.
- Mixing ashift values in a pool — older disks with 512-byte
sectors combined with newer 4K disks force ashift=9, which wastes
space. Create pools with
ashift=12on modern disks. - Forgetting to set up scrubs — without a scrub schedule, silent corruption is detected only when ZFS tries to read a corrupt block, which can be after the second copy is also bad. Schedule a weekly scrub.
Key takeaways
- ext4 is the simple default. ZFS is the production-grade choice.
- ZFS requires direct disk access; no hardware RAID.
- Schedule weekly scrubs. Compression is free. Dedup is expensive.
- Match recordsize to your workload; 64K is the safe default.
Knowledge check
Knowledge check · 4 questions
Q1. Why is hardware RAID incompatible with ZFS for VM storage?
Q2. ZFS dedup needs its table resident in RAM, on the order of 5 GB per TB of unique data, before it saves anything.
Q3. How often should you scrub a ZFS pool used for VM storage?
Q4. Which of these are valid defaults for a ZFS VM storage dataset? (Select all that apply)
Passing score: 75%. Answers are checked in this browser.