zrepl treats ZFS snapshots as the unit of backup and replication
One-stop ZFS backup & replication solution
At a glance
- What is it?
- zrepl is a Go tool that backs up and replicates ZFS datasets by sending incremental ZFS send streams between pools, with a configuration model built around jobs, bookmarks and the replication planner. It is MIT licensed, at version 0.7.0, and the last push was on 2026-05-19.
- Who is it for?
- zrepl suits a ZFS administrator who wants replication that understands snapshots rather than a file level copier pointed at a mount, and it is the wrong tool if your storage is not ZFS or if you need a tool that also does cross platform restore. Before adopting it, read the user documentation at zrepl.github.io, because the configuration is the hard part and the README deliberately does not reproduce it.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 156 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
ZFS send streams, not files over a network
zrepl is a one-stop ZFS backup and replication solution, written in Go and using Go modules to manage dependencies.
The important thing about the design is what it replicates. zrepl works at the level of ZFS datasets and snapshots, sending the incremental stream that ZFS itself produces, so a replication is a set of filesystem transactions rather than a file walk. The repository topics list backup, bookmark, incremental, replication, snapshot and zfs, and each of those is a piece of that model.
The bookmark concept is the one that is specific to zrepl. A ZFS snapshot is a filesystem object with a name, and a bookmark is a lightweight reference to a snapshot that survives some of the operations a snapshot does not. Using bookmarks is how zrepl tracks what it has already replicated, so it knows which increment to send next rather than resending from a full sync. The incremental topic tag and the bookmark tag are the two halves of that.
The dependency list supports the same reading. The go.mod pulls in lib/pq and go-sql-driver/mysql, which are database drivers, and robfig/cron for scheduling, plus cobra and pflag for the command line, and prometheus/client_golang for metrics. There is also gdamore/tcell, a terminal UI library, which tells you the tool has an interactive console, and go-logfmt/logfmt for structured log output, which is what you want in a log that a machine parses.
The zrepl/yaml-config dependency is notable because it is a fork of the configuration library, which means the project has had to change configuration behaviour that the upstream library did not offer, and it has carried that fork rather than working around it.
The configuration is a job graph and a planner
The README does not reproduce the configuration reference, and that is deliberate. It points to the user documentation at zrepl.github.io, and the repository has a docs/ directory with the source for it, written in reStructuredText using the Sphinx framework.
The shape of the configuration is visible from the repository structure and the topics. A job describes what to do, a bookmark names what has been replicated, and the replication planner decides the order in which datasets are synced so that a dataset is not replicated before its parents. That planner is the part that makes zrepl different from a cron job that calls zfs send, because a ZFS hierarchy has dependencies and a naive scheduler will try to replicate a child before its parent exists on the receiving side.
The go.mod gives a hint of how the configuration is validated. The go-playground/validator appears twice, once at the v9 line and once at v10, which suggests a migration in progress rather than a clean single version, and validation of a large YAML file is exactly the kind of thing that library is for. The config is then loaded through a fork, zrepl/yaml-config, so the project can control how the file is read.
The tool also keeps a database. The MySQL and PostgreSQL drivers are both direct dependencies, and there is a directory named dist/ and a debian/ directory for packaging, plus a packaging/ directory. A tool that tracks replication state across datasets and across time needs somewhere to keep that state, and supporting two database engines is a deliberate choice for a tool that runs on servers where one or the other is already installed.
Testing splits into pure Go and root required platform tests
The test story is described in enough detail to be worth quoting, because it explains how a project like this validates itself. The two test commands are:
make test-go
sudo make test-platformThe test suite is split into pure Go tests, make test-go, and platform tests that interact with ZFS and thus generally require root privileges, sudo make test-platform. Platform tests run on their own pool with the name zreplplatformtest, which is created using the file vdev in /tmp.
That pool name and the vdev file are the details that matter. A ZFS test needs real datasets, and creating them needs the zfs command, which needs privileges, so the platform tests are a separate target that a developer runs deliberately and that CI runs in a container with the right capabilities. Isolating them into a named pool keeps them from touching a developer's real data.
For a full code coverage profile the README gives the sequence make test-go COVER=1 && sudo make test-platform && make cover-merge, and an HTML report can be generated using make cover-html. The merge step exists because the two test runs produce coverage data in different formats for different binaries, so the coverage of the pure Go code and the coverage of the code that only the platform tests reach have to be combined before the report means anything.
The Makefile also shows the coverage tooling dependency, gocovmerge, and the pkg/profile and pprof packages in go.mod, which is how the CPU profiling of the test runs is captured.
Releases are tags, artefacts are signed, and the process is written down
The release procedure in the README is unusually complete, and it is a good indicator of how seriously the project takes its artefacts.
All zrepl releases are git-tagged and then published as a GitHub Release. There is a git tag for each zrepl release, usually vMAJOR.MINOR.0. We don't move git tags once the release has been published.
The steps are: prepare the release as a pull request to master, finalizing docs/changelog.rst and updating the supporters list, merge it, at which point the docs are auto-published to zrepl.github.io. Then tag the release on the master branch with make tag-release ZREPL_TAG_VERSION=v0.7.0 and push the tag. Then run the release pipeline against master, which is triggered through the CircleCI UI, and download the artefacts with make download-circleci-release JOB_NUM=66079, where JOB_NUM must be the job number from the release-upload job and not the pipeline number, a distinction the README spells out with a URL to find it.
Then verify checksums and sign the checksums file with make verify-and-sign. Then create the GitHub draft release and upload the artefacts, review the draft and publish it with the box checked to create a GitHub Discussion for the release, and finally link the release from the changelog and the versions template and announce it in the Matrix channel.
After a couple of days the .rpm and .deb files are added to the official zrepl repositories, with the code for managing those repositories in a private repository.
The CircleCI setup has two workflows. The ci workflow runs for every commit, branch or tag pushed to GitHub, is supposed to run very fast, under five minutes, and provides quick feedback to developers, and it runs formatting checks, lints and tests on the most important operating systems and architectures. The release workflow runs on manual triggers through the CircleCI API and periodically on master.
The releases are v0.6.0 in November 2022, v0.6.1 in October 2023 and v0.7.0 in February 2026, with the last push on 2026-05-19.
Where zrepl is the wrong choice
The first limit is that ZFS is not optional. The whole design rests on datasets, snapshots, bookmarks and the send and receive primitives, and there is no filesystem mode. If your storage is ext4, btrfs or a cloud block device, this tool has nothing to say to you, and the alternatives in the ZFS specific space are the other ZFS tools.
The second is that replication is not backup, or at least not the kind a compliance regime recognises. A replicated dataset protects against the loss of one machine. It does not protect against the loss of both the source and the target, against a mistaken deletion that propagates, or against corruption that was already in the snapshot. A backup solution with independent retention and a restore path is a different tool, and the README describes zrepl as a backup and replication solution without making that distinction for you.
The third is the configuration complexity. The README is short because the configuration lives in a separate documentation site, and that is a warning as much as a convenience. A zrepl configuration describes datasets, jobs, bookmarks and a scheduling plan, and getting a plan wrong means a snapshot is not replicated, which is a failure that is silent until you need it. The planner exists to catch some of that, and the validation library catches schema errors, and neither catches a job that was never defined.
The fourth is the release cadence against the risk. The gap from v0.6.1 in October 2023 to v0.7.0 in February 2026 is more than two years, and the project is candid about why in the patch release section, saying that vMAJOR.MINOR.0 is typically a tagged commit on master because development velocity isn't high and thus release branches for stabilization aren't necessary. For a tool that sends data between pools, a long gap means either you run an old version or you adopt a new one with a large jump, and the README documents a separate procedure for patch releases and package rebuilds.
The fifth is the operational privilege. The platform tests need root, which is a reasonable proxy for what the tool does in production, since replication means holding ZFS send and receive capabilities, and a tool that can create and destroy datasets is a tool whose configuration is security sensitive.
Editorial conclusion
zrepl suits a ZFS administrator who wants replication that understands snapshots rather than a file level copier pointed at a mount, and it is the wrong tool if your storage is not ZFS or if you need a tool that also does cross platform restore. Before adopting it, read the user documentation at zrepl.github.io, because the configuration is the hard part and the README deliberately does not reproduce it. Verify first that the version of ZFS on both sides supports the send and receive features zrepl needs, and note that the platform tests require root privileges, which tells you how much of the behaviour is only testable against a real pool.
Frequently asked questions
What is zrepl?
It is a one-stop ZFS backup and replication solution written in Go. It works at the level of ZFS datasets and snapshots, sending incremental streams between pools, with jobs, bookmarks and a replication planner that determines the order in which datasets are synchronised.
How do I build and test zrepl?
The build needs Go, GNU Make, Git, and wget and unzip for make generate. Tests split into pure Go tests with make test-go and platform tests that interact with ZFS and need root with sudo make test-platform, running on a pool named zreplplatformtest created from the vdev file in /tmp.
How are zrepl releases made?
Releases are git-tagged, usually vMAJOR.MINOR.0, and published as a GitHub Release, and tags are never moved. The process prepares docs/changelog.rst in a pull request, tags with make tag-release, runs the release pipeline on CircleCI, downloads the artefacts with make download-circleci-release, then verifies and signs the checksums with make verify-and-sign before creating a draft release and publishing it.
Where is the zrepl configuration documented?
In the user documentation at zrepl.github.io, whose sources are in the docs/ directory and are written in reStructuredText with Sphinx. The README deliberately does not reproduce the configuration reference and links to the site instead.
What licence is zrepl released under?
MIT, with the LICENSE file at the top of the repository. The current release is v0.7.0 from 2026-02-15 and the last push was on 2026-05-19, and the project is funded through Patreon, GitHub Sponsors, Liberapay and PayPal.
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/zrepl-zrepl)Was this useful?