Sanoid and syncoid: policy-driven ZFS snapshots and replication
These are policy-driven snapshot management and replication tools which use OpenZFS for underlying next-gen storage. (Btrfs support plans are shelved unless and until btrfs becomes reliable.)
At a glance
- What is it?
- Sanoid decides which ZFS snapshots to keep from a TOML policy file, and syncoid copies them to another host. The pair fits ZFS pools with a regular snapshot schedule; it is not a backup product with its own catalog, and it assumes OpenZFS underneath.
- Who is it for?
- Adopt Sanoid if you already run OpenZFS on Linux or FreeBSD and want snapshot retention expressed as one TOML file rather than a pile of shell scripts. Do not adopt it if you need an application-consistent backup catalog, or if you expect it to manage a filesystem other than ZFS: the README states that Btrfs support plans are shelved.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 117 days ago.
- What is it written in?
- Mainly Perl, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Sanoid solves for ZFS pool owners
ZFS gives you snapshots and zfs send, but it does not give you a retention policy. Left alone, a pool accumulates snapshots until someone writes a pruning script, and those scripts tend to be brittle because they have to reason about hourly, daily, weekly and monthly buckets at once. Sanoid's job is to own that reasoning. You declare how many of each interval you want to keep, and the tool takes new snapshots and expires old ones on every run.
The intended user is someone who already administers a ZFS pool and is comfortable with cron. The README frames the extreme case, combining Sanoid with Linux KVM to make systems "functionally immortal" through automated snapshot management and over-the-air replication, and points at a demo of rolling back a cryptomalware infection. That framing is promotional, but the underlying primitive is real: a snapshot you can roll back to is the difference between an incident and a rebuild.
Sanoid is not the only piece. The repository ships two main scripts, sanoid for local snapshot policy and syncoid for replication, plus smaller helpers such as findoid, findbay and check_all_disk_space. The topics on the repository are replication, snapshot and zfs-filesystem, which describes the scope accurately.
How the TOML policy file drives snapshot and prune runs
The mechanism is a single configuration file at /etc/sanoid/sanoid.conf, read on every invocation. Sections are dataset paths; the values are retention counts and two switches, autosnap and autoprune. A separate file, /etc/sanoid/sanoid.defaults.conf, supplies values for any interval you leave out, and the README states that it is not user-editable. That is worth internalising: if you omit an interval, you inherit a default rather than getting zero.
The README's example keeps 36 hourly, 30 daily, 4 weekly, 3 monthly and no yearly snapshots for datasets under data/images, with recursive and process_children_only set so the parent dataset itself is skipped. A child dataset can then override one value without restating the rest, which is how the example reduces data/images/win7 to 4 hourlies. Templates are ordinary sections named template_*, referenced with use_template.
A run is stateless apart from a cache. Sanoid maintains a ZFS snapshot listing cache, defaulting to /var/cache/sanoid, with a 20 minute TTL that --cache-ttl can change and --force-update can clear. The command line splits the work: --cron does both snapshot creation and pruning, --take-snapshots creates without pruning, and --prune-snapshots prunes without creating. The README notes that snapshots are atomic within a single dataset, not globally: pool/dataset1 and pool/dataset2 are each internally consistent, but one may be a few filesystem transactions newer than the other. For anything spanning multiple datasets, that gap is the thing to design around.
Installing Sanoid and taking a first snapshot
The repository ships a packages/ directory and an INSTALL.md, so distribution packaging is the expected path on Linux; the README itself only shows the cron line and assumes the binaries are already in place. The README's cron example uses /usr/local/bin/sanoid, which is where a source install tends to land. Check INSTALL.md for your platform before copying that path.
Once installed, two files matter. The user-editable policy lives in sanoid.conf; the defaults file must also be present, and the README is explicit that it is not user-editable.
# confirm the binary and its version
/usr/local/bin/sanoid --version
# inspect what the policy would do without changing anything
/usr/local/bin/sanoid --readonly --verbose--readonly skips creation and deletion, and --verbose adds detail. Run both before you let the tool touch the pool, because a misread retention count is only visible in what it intends to delete.
A minimal policy for one dataset looks like the README's structure, with the template below the dataset sections:
[data/home]
use_template = production
[template_production]
frequently = 0
hourly = 36
daily = 30
weekly = 4
monthly = 3
yearly = 0
autosnap = yes
autoprune = yesWith that in place, the scheduled run is the README's single cron entry. The UTC setting is recommended there to avoid daylight saving problems, and it is easy to drop when copying the line.
* * * * * TZ=UTC /usr/local/bin/sanoid --cronAfter the first run, zfs list -t snapshot should show snapshots named from the intervals you configured. If nothing appears, check that autosnap is yes and that the dataset path in the config matches the pool name exactly.
Monitoring, script hooks and the Nagios-shaped interface
Three command line options exist purely to feed a monitoring system: --monitor-snapshots reports on snapshot health, --monitor-health on the health of the zpool holding your configured filesystems, and --monitor-capacity on pool capacity. All three are described as designed to be run by Nagios, and all three restrict themselves to datasets and pools named in sanoid.conf. If a pool is not in the config, it is invisible to monitoring. That is a deliberate scoping choice, and it means your monitoring coverage is exactly as wide as your policy file.
Sanoid also exposes three hook points in the snapshot lifecycle: pre_snapshot_script, post_snapshot_script and a pruning script. The README notes that snapshot hooks fire only when autosnap = yes and pruning hooks only when autoprune = yes, so a dataset with pruning disabled never runs its prune hook. Hooks receive environment variables, including SANOID_SCRIPT to tell one script which stage it is in, SANOID_TARGETS as a comma separated dataset list, and SANOID_SNAPNAMES for the snapshot names without the dataset prefix. SANOID_TARGET and SANOID_SNAPNAME are marked deprecated in the README because they only carry the first dataset or name; new scripts should read the plural variables. The README also notes that SANOID_TARGETS currently holds a single dataset, with multiple datasets described as a future possibility for atomic groups, so the plural form is an interface that is ahead of the implementation.
Where Sanoid is the wrong tool
The most concrete limitation is stated by the project itself: Btrfs support plans are shelved unless and until btrfs becomes reliable. If your storage is not OpenZFS, Sanoid is not for you, and the repository does not pretend otherwise.
A second boundary is the atomicity note. Because snapshots are atomic per dataset and not across the pool, a dataset pair that must agree with each other will not be captured at one instant. Applications that need a consistent view across several datasets, such as a database split over multiple datasets, need their own quiescing step in a pre_snapshot_script rather than relying on Sanoid to freeze everything at once.
A third is the shape of the tool. Sanoid is a cron-driven script that reads a config file and calls ZFS. It has no scheduler daemon, no job queue, no web interface, and no catalog of what was backed up where. Retention is expressed as counts per interval, so if you need retention by age, by size, or by a compliance rule that does not map onto hourly/daily/weekly/monthly buckets, you are working against the model rather than with it. And because pruning runs on the same schedule as creation, a config mistake can delete snapshots on the first --cron run; --readonly exists precisely for that reason.
Sanoid versus syncoid, and versus zfs-auto-snapshot
The most common confusion is treating Sanoid and syncoid as alternatives. They are not. Sanoid runs on the machine that owns the pool and manages local snapshots according to the policy file. syncoid is the replication half: it uses zfs send and zfs receive to copy snapshots to another pool or another host, and its own release notes for v2.2.0 mention syncoid direct connection support. A typical setup has Sanoid creating snapshots on the source and syncoid shipping them to a target, which is why the repository's topics list replication and snapshot together. If your question is which one to install, the honest answer is that they solve different halves of the same problem.
The closer comparison is zfs-auto-snapshot, which also creates and expires snapshots on a schedule. The difference in approach is where the policy lives and how much it can express. zfs-auto-snapshot is built around fixed interval labels applied to datasets, and its configuration is per-dataset properties and script arguments. Sanoid centralises retention in one TOML file with templates and inheritance, supports recursive application with process_children_only, and adds monitoring modes and lifecycle hooks in the same binary. If you want a small script that snapshots everything on a fixed schedule, zfs-auto-snapshot is simpler. If you want per-dataset retention counts, template reuse and hook points, Sanoid's config model is the reason to pick it.
Maintenance, releases and licence
The repository is not archived, and the last push was on 2026-06-05. Releases are infrequent and chunky rather than continuous: v2.3.0 arrived on 2025-06-11 with fast cache updates, documentation, performance updates and bugfixes, v2.2.0 on 2023-07-18, and v2.1.0 on 2021-04-01. That cadence matters for planning. You should not expect a fix for a niche problem to land in the next few weeks, and you should read the CHANGELIST rather than assume behaviour is unchanged between major versions.
The upgrade cost is mostly in the config surface. Sanoid reads sanoid.conf and sanoid.defaults.conf, and the defaults file is not meant to be edited, so a new release can change inherited defaults for any interval you left unspecified. Datasets that relied on an implicit default can therefore change behaviour without any edit on your side. Pinning the intervals you care about explicitly in your own template is the cheap defence. The cache TTL default of 20 minutes is another value a release can touch.
Licensing is GPL-3.0, stated in the LICENSE file and in the README, which describes Sanoid as free and libre now and in perpetuity under that licence. For internal use on your own infrastructure this is unremarkable. If you plan to redistribute Sanoid inside a product, or to link it into a proprietary appliance, the GPL-3.0 obligations are the thing to have a lawyer read, not a summary here. The README also asks for donations via Patreon or PayPal to support the project and the Practical ZFS forum; that is a funding request, not a support contract, so do not read it as a guarantee of response times.
Editorial conclusion
Adopt Sanoid if you already run OpenZFS on Linux or FreeBSD and want snapshot retention expressed as one TOML file rather than a pile of shell scripts. Do not adopt it if you need an application-consistent backup catalog, or if you expect it to manage a filesystem other than ZFS: the README states that Btrfs support plans are shelved. Before putting it in production, verify three things on your own pool: that /etc/sanoid/sanoid.defaults.conf exists, that your cron entry sets TZ=UTC, and that sanoid --readonly reports the snapshot set you expect before you let it delete anything.
Frequently asked questions
What is Sanoid?
Sanoid is a policy-driven snapshot management tool for ZFS filesystems, written in Perl and licensed GPL-3.0. It creates, automatically thins and monitors snapshots and pool health from a TOML config file at /etc/sanoid/sanoid.conf.
How do I install Sanoid?
The README does not give install steps; it points to INSTALL.md, and the repository contains a packages/ directory, so distribution packaging is the expected route on Linux. The README's cron example assumes the binary is at /usr/local/bin/sanoid.
How do I use Sanoid?
Write dataset sections and a template in /etc/sanoid/sanoid.conf, then run sanoid --cron from cron with TZ=UTC set, as the README shows. --take-snapshots creates without pruning, --prune-snapshots prunes without creating, and --readonly simulates a run.
What is the difference between Sanoid and syncoid?
Sanoid manages local snapshots according to the policy file on the machine that owns the pool. syncoid is the replication tool that copies snapshots to another pool or host, and the v2.2.0 release notes mention syncoid direct connection support.
Is Sanoid an alternative to zfs-auto-snapshot?
Both create and expire ZFS snapshots on a schedule, but Sanoid centralises retention in one TOML file with templates and inheritance, and adds monitoring modes and lifecycle hooks. zfs-auto-snapshot applies fixed interval labels to datasets instead.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jimsalterjrs-sanoid)