Proxmox will let you install onto ZFS during setup with a few checkboxes and move on with your life, and that’s exactly how a lot of people end up with a storage layout they didn’t actually choose. ZFS is the best storage option built into Proxmox for most homelab setups, but it comes with tradeoffs that are easy to ignore during install and expensive to fix once you’ve got VMs and containers living on top of it. Here’s what the pool layout choices actually mean, what ZFS does to your RAM, and how to pick a shape you won’t be re-doing in six months.
Why ZFS over the alternatives
Proxmox supports several storage backends: LVM, LVM-thin, plain directories on ext4/xfs, ZFS, and Ceph for clusters. For a single node or small home cluster, ZFS is usually the right default because it gives you three things none of the simpler options bundle together:
- Checksumming on every block, so silent bit rot gets caught and, if you’ve got redundancy, corrected automatically. LVM and ext4 don’t do this at all, they trust the disk.
- Snapshots that are actually cheap. ZFS snapshots are copy-on-write, near-instant to create, and don’t slow down over time the way LVM snapshots can.
- Built-in redundancy (RAIDZ) without needing a hardware RAID card, plus the ability to add compression and easily replace failing disks.
The cost is RAM usage and a steeper set of decisions up front. If you’re running a single-disk box with no redundancy plans and don’t care about snapshots or checksumming, plain LVM-thin is lighter and simpler. For anything with more than one disk that you want to trust, ZFS is worth the tradeoffs.
RAIDZ levels: what you’re actually choosing between
ZFS’s RAID equivalents are RAIDZ1, RAIDZ2, RAIDZ3, and mirrored vdevs. This is the decision that’s hardest to undo later, because changing RAIDZ level means rebuilding the pool from scratch and restoring everything onto it, there’s no in-place conversion.
- Mirror (RAID1-equivalent). Two or more disks holding identical copies. Best random I/O performance of the redundant options, since ZFS can read from whichever mirror disk is fastest, and the simplest to expand later (add another mirror pair as a new vdev). Costs you 50% of raw capacity with a 2-disk mirror. This is what you want for VM/container storage where I/O responsiveness matters more than raw capacity.
- RAIDZ1. One disk’s worth of parity across the vdev, survives one disk failure. Efficient on capacity (with 4 disks you get 3 disks’ worth of usable space) but the danger is well documented at this point: with today’s large drives, a rebuild after a failed disk can take long enough, under heavy read load, that a second disk failing mid-rebuild is a real risk, not a theoretical one. Most guidance now says skip RAIDZ1 for drives above roughly 4-6TB.
- RAIDZ2. Two disks’ worth of parity, survives two simultaneous failures. This is the sane default for a home NAS-style pool built from larger drives, since it tolerates a second failure during a rebuild window.
- RAIDZ3. Three disks’ worth of parity, survives three failures. Overkill for most home setups unless you’re building a large array (10+ disks) where the statistical odds of multiple failures during a long rebuild start to matter more.
For Proxmox specifically, split your thinking into two separate pools if your hardware allows it: a fast mirror (or even a single disk, if you accept the risk) for the actual VM/container disks where low latency matters, and a RAIDZ2 pool built from larger, slower drives for bulk storage, ISOs, backups, and anything read-heavy rather than latency-sensitive. Mixing both jobs onto one RAIDZ pool of spinning disks works, but you’ll feel it as VM disk latency under load, especially with several VMs doing I/O at once.
ARC and your RAM budget
ZFS caches aggressively in RAM through something called the ARC (Adaptive Replacement Cache), and by default it will use up to half your system’s RAM for it. On a dedicated NAS box that’s usually fine and even desirable, more cache means faster reads. On a Proxmox host, where that same RAM is also what your VMs and containers need to actually run, it can quietly starve everything else if you don’t account for it.
A few practical points:
- ZFS ARC shrinks dynamically when other processes need memory, it’s not a hard reservation, but the shrinking isn’t instant and can cause pressure under sudden load spikes.
- If you’re running Proxmox on a box with 32GB of RAM or less and also running several VMs, cap ARC explicitly rather than trusting the default 50% ceiling. Set
zfs_arc_maxin/etc/modprobe.d/zfs.conf(in bytes) and reboot or reload the module for it to take effect. - A reasonable starting cap for a mixed-use Proxmox host: leave enough RAM for your VMs’ allocated memory plus the Proxmox host itself, and let ARC use most of what’s left, rather than the blanket 50% default. On a 64GB host running 32GB of VMs, capping ARC around 16-20GB instead of the default ~32GB avoids memory pressure without giving up much cache benefit.
- Don’t cap it too low either. ARC below a few GB defeats a lot of the point of using ZFS for VM storage in the first place, since read performance for anything not already cached drops to raw disk speed.
Compression: turn it on, it’s not a hard choice
Unlike RAIDZ level, this one’s easy. Set compression=lz4 (Proxmox’s default when you create a ZFS pool through the UI, but worth confirming with zfs get compression <pool>) on every dataset. LZ4 is fast enough that it typically speeds up effective I/O rather than slowing it down, since less data physically has to move to and from disk, and it costs you almost nothing in CPU on any hardware built in the last decade. There’s essentially no reason to leave compression off on a modern system.
Ashift: set it right at pool creation, because you can’t fix it after
ashift tells ZFS what sector size to assume for the underlying disks, and it’s fixed permanently when the pool is created, no way to change it without rebuilding the pool. Get this wrong and every write pays a penalty for the rest of the pool’s life.
- Most modern drives, both HDDs and SSDs, use 4K physical sectors even if they report 512-byte logical sectors for compatibility (512e). For these, you want
ashift=12(2^12 = 4096). - Proxmox’s ZFS pool creation UI usually auto-detects this correctly, but it’s worth checking, especially on older drives or ones behind a controller that might report sizes inconsistently. Confirm with
zdb -C <pool> | grep ashiftafter creation, before you’ve put real data on it. - If you get ashift wrong (too low), you won’t see errors, you’ll just eat a silent, permanent performance penalty from write amplification. This is a check-once, get-it-right-once setting, not something that surfaces as an obvious problem later.
Don’t fill the pool
ZFS performance degrades as a pool fills up, more noticeably than most other filesystems, because its copy-on-write design needs contiguous free space to work efficiently. Once a pool crosses somewhere around 80% full, fragmentation and write performance both start getting worse, and it gets progressively worse the closer you get to full. Plan your pool size with real headroom, not just enough to fit what you’re storing today, and keep an eye on zpool list capacity percentage rather than finding out about this the hard way during a big write.
Bottom line
ZFS is worth using for Proxmox storage on basically any multi-disk homelab setup, but two decisions matter more than the rest and are both effectively permanent once made: your RAIDZ level (mirror for VM latency, RAIDZ2 for bulk capacity, skip RAIDZ1 on large modern drives) and your ashift value (12, almost always, confirm it before writing real data). Cap ARC deliberately if you’re RAM-constrained rather than trusting the default, turn on lz4 compression everywhere since there’s no real downside, and leave real headroom in the pool instead of running it near full. Get those right at creation time and ZFS mostly runs itself from there.