ZFS snapshots are cheap, instant and atomic, which makes them easy to accumulate into something useless: thousands of snapshots nobody prunes, on a pool with no second copy. TrueNAS SCALE gives you the tools — periodic snapshot tasks, replication tasks, and dataset-level control — but the layout decision in front of them is what determines whether a restore takes minutes or days.
1. Lay out datasets for recovery, not for tidiness
One dataset per data class, and replication at the dataset boundary:
/mnt/tank
├── tank/vm # zvols for VMs — replicate every 15 min
├── tank/containers # docker appdata — replicate hourly
├── tank/media # photos, video — replicate daily
└── tank/documents # irreplaceable — replicate hourly + cloud copy
A single tank/data dataset means a replication task for photos carries the write amplification of the whole pool, and a rollback of one file class rolls back everything. Split them.
Recordsize matters for the same reason: recordsize=16K for VM zvols (with volblocksize=16K at creation), 1M for media, default 128K for mixed. You cannot change a zvol's blocksize after creation — recreate the zvol and copy the data before it holds anything important.
2. Snapshot tasks
Via the UI: Data Protection → Periodic Snapshot Tasks. Via CLI, so it is reviewable and repeatable:
midclt call pool.snapshottask.create '{
"dataset": "tank/containers",
"recursive": true,
"naming_schema": "auto-%Y-%m-%d_%H-%M",
"schedule": {"minute": "0", "hour": "*"},
"lifetime": "14",
"enabled": true
}'
recursive: true is the important flag: it snapshots child datasets atomically, which keeps a database directory and its config in the same instant.
lifetime is in days and is the only thing stopping snapshot sprawl. Twelve snapshots of a churning docker appdata can be hundreds of GB of space that ZFS cannot reclaim until they expire.
3. Replication to the second copy
A snapshot on the same pool is not a backup. Replicate to a second pool — internal, USB-attached for cold copies, or a second NAS:
midclt call replication.create '{
"name": "containers-to-backup",
"direction": "PUSH",
"transport": "SSH",
"source_datasets": ["tank/containers"],
"target_dataset": "backup/containers",
"recursive": true,
"auto": true,
"retention_policy": "SOURCE",
"ssh_credentials": {"host": "backup.lan", "private_key": 1},
"schedule": {"minute": "30", "hour": "*"}
}'
retention_policy: SOURCE means the destination keeps the same snapshots as the source — you prune in one place. CUSTOM lets the destination keep more, which is what you want for the off-site copy where bandwidth limits how often you can ship: keep dailies locally for a week, keep monthlies remotely for a year.
4. Test a rollback, not just a send
# what exists
zfs list -t snapshot -o name,used,refer tank/containers | tail -5
# non-destructive check: mount a snapshot and compare
zfs clone tank/containers@auto-2026-10-20_09-00 tank/restore-test
ls /mnt/tank/restore-test
zfs destroy tank/restore-test
# the real thing: roll back a dataset
zfs rollback -r tank/containers@auto-2026-10-20_09-00
zfs rollback -r destroys every snapshot newer than the target. On a replicated dataset that divergence is then pushed to the destination on the next run — which is correct, and also why you test on a clone first.
Pitfalls
- Snapshots are not free on write-heavy datasets. They pin blocks. A 12-snapshot rotation on a churning zvol can consume more space than the zvol itself.
zfs rollbackis local only. The remote keeps its older chain until the next replication sync; checkzfs list -t snapshoton both sides, not just the source.- Replication before the snapshot task runs silently sends nothing. Order the schedules or use
auto: true, which replicates the newest common snapshot. - Scrubs are not optional. Schedule a monthly scrub on both pools; that is how ZFS detects bit rot before your restore discovers it.
- Encryption keys. If a dataset is encrypted, the replication target needs the key to mount. Test that the key exists in a password manager, not only in the boot pool.
A snapshot without an off-pool copy is a rollback convenience, not a backup. Both, or neither counts.