Btrfs vs ZFS for Homelab Storage — Which Filesystem Should You Choose?
If you run a homelab with Proxmox and Docker, you will eventually face the Btrfs vs ZFS question. Both are advanced copy-on-write filesystems with checksumming, snapshots, and compression. Both have passionate advocates. And both work with Proxmox VE.
The short answer: use ZFS for your hypervisor storage and Btrfs for your Docker container volumes. But the full picture depends on your hardware, workload, and comfort with tuning.
This guide compares both filesystems across the metrics that actually matter in a homelab: memory use, Docker compatibility, snapshot workflows, compression performance, and pool management flexibility.
Architecture and Kernel Integration
The first difference is architectural. ZFS is not part of the Linux kernel — it ships as an external DKMS module maintained by the OpenZFS project. Every kernel update triggers a rebuild of zfs.ko and spl.ko. On Proxmox this is handled automatically, but you will occasionally hit a delay between a kernel release and the matching ZFS module.
Btrfs lives in the Linux kernel tree, maintained by kernel developers. It compiles as part of btrfs.ko and is always compatible with whatever kernel you are running.
|
|
For daily use, most people will never notice the difference. The DKMS rebuild takes a few seconds during upgrades. But if you run custom kernels or frequent edge releases, Btrfs wins on simplicity.
Memory Usage — The ZFS ARC Tax
This is the area where Btrfs has a clear advantage in RAM-constrained homelabs.
ZFS uses an Adaptive Replacement Cache (ARC) that eagerly consumes available memory. By default, ZFS can claim up to 50% of system RAM. On a 16 GB Proxmox host, that means 8 GB reserved for the ARC before any VMs start. You can clamp it:
|
|
Btrfs uses the standard Linux page cache. It does not pre-allocate memory, does not have an ARC, and yields memory to applications when needed. On a 4 GB or 8 GB homelab node, Btrfs will leave noticeably more RAM for your workloads.
The rule of thumb: ZFS can be used comfortably with 8 GB+ RAM. Below that, running ZFS becomes a tradeoff. Btrfs works well on anything with 2 GB or more.
Data Integrity and Checksumming
Both filesystems checksum data and metadata. Both can detect and repair silent data corruption when redundancy is available.
ZFS checksums every block via a Merkle tree. When configured with mirrors or raidz, it performs automatic self-healing — if one copy is corrupt, ZFS fetches a good copy and repairs the bad one.
|
|
Btrfs also checksums data and metadata. Self-healing works on RAID levels 1, 10, and (with caveats) 5 and 6.
|
|
In practice, both handle data integrity well. ZFS is more battle-tested here, especially at scale. Btrfs has had RAID56 corruption issues that are still being resolved — if you need RAID5/6, pick ZFS.
Docker Storage Drivers
If you run Docker containers heavily, the storage driver matters.
Docker on ZFS: The zfs storage driver creates a ZFS dataset per image layer. It works well but does not support overlay2 — Docker skips the overlay layer model entirely. Performance is generally good, but container writes go through ZFS datasets instead of the overlay union filesystem.
|
|
Docker on Btrfs: Docker uses the native overlay2 driver with Btrfs as the backing filesystem. Snapshots are used for layer management. This is the same code path as ext4/XFS but with Btrfs-level snapshot capabilities.
|
|
For container-heavy workloads, Btrfs + overlay2 is measurably faster for layer operations and is the simpler configuration. Docker’s own documentation recommends overlay2 as the preferred driver.
|
|
If you run Docker inside a Proxmox LXC container (which many homelabbers do), the container itself uses a ZFS dataset. But inside that LXC, Docker writes to ext4 or Btrfs depending on how the LXC is configured. Btrfs gives you the overlay2 path natively.
Compression Performance
Both filesystems offer transparent compression. On modern hardware with AES-NI and multi-core CPUs, compression is essentially free for data workloads.
ZFS uses lz4 by default, which is incredibly fast. Newer pools can use zstd at compression levels 1 through 19.
|
|
Btrfs supports zstd, lzo, and zlib. Zstd at level 1 (zstd:1) is the recommended balance of speed versus compression.
|
|
In benchmarks, lz4 (ZFS) and zstd:1 (Btrfs) offer comparable performance. Zstd typically compresses 5-15% better than lz4 at level 1, with similar CPU cost.
Snapshot and Replication Workflows
This is where both filesystems really shine. Native snapshots and send/receive are the killer features that make them worth choosing over ext4 or XFS.
ZFS snapshots are instant, space-efficient, and can be sent incrementally via zfs send -i.
|
|
Btrfs snapshots are also instant. Send/receive works similarly but uses a different syntax.
|
|
Both workflows are production-grade. ZFS send/receive is more widely documented, but Btrfs send/receive has matured significantly and works reliably across machines.
Pool Management and RAID
ZFS pools consist of vdevs. You cannot add a single disk to an existing vdev — you add an entire vdev (mirror or raidz). You cannot shrink a pool. Pool expansion is planned in OpenZFS but not yet stable.
|
|
Btrfs allows adding and removing devices from an existing filesystem. You can start with two disks in RAID1 and add a third later.
|
|
For flexibility with mixed disk sizes, Btrfs is the clear winner. For fixed, redundant pools you will never change, ZFS is equally capable.
Quotas and Resource Limits
ZFS quotas are mature and reliable:
|
|
Btrfs qgroups have a history of inconsistency, especially with snapshots. They work for basic cases but can produce surprising results under snapshot-heavy workloads. For Docker use cases, the standard filesystem-level quotas (quota mount option with project quotas) are more reliable.
|
|
If quotas are critical for multi-tenant setups, ZFS wins here.
Proxmox Integration
Proxmox VE installs with either ext4, XFS, or ZFS as the root filesystem. Btrfs is not an installer option but can be configured manually.
For the hypervisor itself, ZFS is the recommended choice because:
- It integrates with Proxmox Backup Server natively
- It provides boot environments for safe upgrades
- Proxmox manages ZFS datasets for VM/LXC storage automatically
|
|
For Docker workloads inside Proxmox, running Docker in a LXC container with Btrfs storage (or even on its own Btrfs-formatted disk) gives you the overlay2 performance advantage.
A common hybrid strategy:
- Proxmox host: ZFS for VM/LXC storage and hypervisor reliability
- Docker LXC: Btrfs subvolume or disk for container storage
Decision Matrix
| Factor | ZFS | Btrfs |
|---|---|---|
| Memory usage | High (ARC) | Low (page cache) |
| Docker storage driver | Non-overlay (zfs) | overlay2 native |
| Data integrity | Battle-tested, mature | Mature for RAID1/10 |
| Snapshots | Excellent | Excellent |
| Quotas | Mature, reliable | Qgroups still maturing |
| Pool flexibility | Cannot add single disk | Add/remove disks freely |
| Kernel integration | DKMS module | In-kernel |
| RAID5/6 | Production grade | Experimental |
| Compression | lz4 (fast), zstd | zstd:1 (best ratio) |
| Proxmox integration | Native installer option | Manual setup |
Choose ZFS when: You have 8 GB+ RAM, need RAID5/6, require reliable quotas, or want the most battle-tested data integrity for the hypervisor.
Choose Btrfs when: You are RAM-constrained, run Docker heavily, want the flexibility to add and remove disks, or prefer deep kernel integration.
The best homelab configuration uses both: ZFS for your Proxmox storage pool and VMs, Btrfs for your Docker container volumes inside a dedicated LXC. You get the reliability of ZFS where it matters and the performance of overlay2 where Docker workloads count.