Every layer of protection covered elsewhere on this site has a specific job. RAID survives a dead drive (see the RAID redundancy guide). Checksums and scrubs catch silent corruption (see bit rot and checksumming). The 3-2-1 strategy (see the backup guide) gets a copy off-site. None of them protect you from the most common actual cause of data loss in a homelab: you, or something acting with your credentials, deleting or overwriting a file that was perfectly healthy a minute ago.
A rm -rf typo doesn’t trip RAID. An *arr app’s bad rename logic doesn’t trip a checksum. A ransomware payload with write access to your share encrypts every file in place, cleanly, with no read errors anywhere. All three of those are instantly and silently replicated by any sync-based backup that runs on a schedule, because as far as that backup is concerned, nothing went wrong, you just deleted or changed a file. This is the gap ZFS snapshots close, and it’s one of the cheapest, lowest-effort protections available to anyone already running ZFS underneath their data hoard.
What a ZFS snapshot actually is
A ZFS snapshot is a read-only, point-in-time view of a dataset, taken instantly regardless of how large the dataset is. It works because ZFS is copy-on-write: a snapshot doesn’t copy any data at creation time, it just freezes a reference to every block that currently exists. When you later modify or delete a file, ZFS doesn’t overwrite the old blocks in place, it writes new blocks for the change and leaves the old ones alone, because the snapshot still references them. The old version of the file is still sitting right there on disk, fully intact, until you explicitly destroy the snapshot that’s holding it.
# take a snapshot
zfs snapshot tank/media@2026-10-15
# list snapshots on a dataset
zfs list -t snapshot -r tank/media
# roll the whole dataset back to a point in time
zfs rollback tank/media@2026-10-15
# recover a single file without rolling back the whole dataset
cp /tank/media/.zfs/snapshot/2026-10-15/missing-file.mkv /tank/media/
That last command is the one that matters day to day. Every ZFS dataset has a hidden .zfs/snapshot/ directory (not visible in a normal ls, but perfectly browsable if you cd into it) that exposes every snapshot as a read-only folder tree. You don’t need to understand zfs rollback or think about pool state to get a single accidentally-deleted file back. You just walk into the snapshot directory and copy it out, the same way you’d dig a file out of an old backup folder, except there was no backup job, no network transfer, and no delay.
Why this beats “I have a backup” for this specific failure mode
A snapshot is not a replacement for an off-site backup, and it never covers you for a dead pool or a destroyed box, that’s still the 3-2-1 strategy’s job. What it covers that a scheduled backup often doesn’t is the time window between the mistake and the backup’s own retention catching it.
Picture a common Restic or Borg setup running nightly with 30 days of retention. If ransomware encrypts your media library at 2 AM and the backup runs at 3 AM, you now have 29 more days of good backups and one bad one, which is fine, you can roll back to yesterday. But if nobody notices for six weeks because it’s a folder you don’t open often, every retained backup is now encrypted, and you’ve lost the window entirely. ZFS snapshots taken frequently (hourly is common, even every 15 minutes costs almost nothing) give you many more restore points inside that same day, and because they’re local and instant, there’s no “did last night’s job even complete successfully” question hanging over whether the good copy actually exists.
The other practical advantage: a snapshot restore for one file is a local cp, done in seconds. Restoring one file from Restic or Borg means a repository scan and a restore operation, which works fine but is slower and depends on the backup target being reachable. For the “I deleted the wrong folder an hour ago” case, which is overwhelmingly the most common real-world incident, a snapshot is just faster.
The ransomware-specific piece: immutability
Snapshots only protect you against ransomware if the ransomware can’t also destroy them. A compromised machine with write access to your NAS share can delete files, but a well-configured ZFS host doesn’t expose zfs destroy to that same share, snapshot management lives at the ZFS/host level, not inside the SMB or NFS export. This is a meaningful structural advantage over, say, Windows VSS shadow copies, which live on the same volume the ransomware already has write access to and are a known, documented target for deletion by real ransomware families before they start encrypting.
The practical setup that actually holds up:
- Take snapshots from the NAS host itself (cron,
sanoid, or your NAS OS’s built-in scheduler), never from a script running on a client machine that also has write access to the share. - Keep the account that mounts the share for day-to-day use (SMB/NFS client, the
*arrstack, whatever writes to it) without any permission to manage ZFS snapshots or pools. If that account is compromised, it should be able to encrypt files, not destroy your recovery path. - If you want a true belt-and-suspenders layer against a fully compromised host,
zfs sendsnapshots to a second system that the primary host has no delete access to (see ZFS send and receive). A snapshot an attacker can’t reach from the compromised box is a snapshot they can’t destroy.
Managing retention without letting snapshots eat your pool
Snapshots are cheap but not free. Every block a snapshot holds onto is a block that can’t be reclaimed until that snapshot is destroyed, even after you delete the “live” copy of the file. A dataset with heavy daily churn (a download/transcode scratch directory, for example) and an aggressive hourly-snapshot policy with no pruning will quietly consume real pool space, and you’ll find out the hard way when zpool list shows less free space than you expected.
The standard tool for this is sanoid, which handles both scheduled snapshot creation and automated pruning against a retention policy you define per dataset, rather than making you hand-write cron jobs and manual zfs destroy calls:
# /etc/sanoid/sanoid.conf
[tank/media]
use_template = production
recursive = yes
[template_production]
hourly = 36
daily = 30
monthly = 3
autosnap = yes
autoprune = yes
That example keeps 36 hourly snapshots (a day and a half of fine-grained recovery points), 30 daily snapshots (a month of daily rollback), and 3 monthly snapshots (a quarter of coarser history), automatically pruning anything older. Tune the hourly count up for datasets where “I need the version from 40 minutes ago” is realistic (active project files, a database), and down for datasets that barely change (a finished media archive you mostly read from).
One sizing habit worth adopting: datasets with high churn and low per-file value (scratch space, transcode temp directories) don’t need deep retention at all, a handful of hourly snapshots is plenty. Datasets with low churn and high per-file value (your actual media library, personal documents, photos) are exactly where retention should be deepest, since the whole point is protecting against a mistake you might not notice for weeks.
Where this fits relative to everything else
Snapshots aren’t a backup strategy on their own, they live on the same pool as the data they’re protecting, so a dead pool, a dead controller, or the whole box getting stolen takes the snapshots down with everything else. They’re also not corruption detection, that’s still checksums and scrubs. What they are is the cheapest, fastest-to-restore-from layer against the single most common real incident: a mistake, a bad script, or a compromised client deleting or overwriting something that was fine a moment ago. If you’re running ZFS already and you don’t have scheduled snapshots turned on, this is one of the highest-value, lowest-effort things you can add to a data hoard today.