A command line backup program that writes encrypted, content-addressed, deduplicated snapshots to a local disk, SFTP, S3-compatible object storage or anything rclone can reach. It replaces a scheduled-backup SaaS subscription with a cron job and a bucket you already pay for.
Our verdict on restic#
restic 0.19.1 (5 July 2026) is still a 0.x release after eleven years, and it is still the sane default for encrypted backups to a storage target you do not trust. Compression arrived in 0.14 with repository format 2, and format 2 is now what restic init creates by default, with --compression auto. If your repository predates that you must run migrate upgrade_repo_v2 and then prune --repack-uncompressed, which rewrites the entire repository and costs you a full repo-sized rewrite of traffic and time. The real ongoing cost is memory: restic loads the repository index into RAM, so prune on a multi-terabyte repo with tens of millions of blobs wants several GB and will be OOM-killed on a 2 GB VPS. The second cost is locking. Any run that dies leaves a lock and the next run refuses to start until you restic unlock or pass --retry-lock 10m (added in 0.16.0). Plan for both before you point it at 5 TB.
Who restic is for#
Choose it if
- Someone who wants one binary in cron backing up a server to a B2 or S3 bucket, with no agent, no daemon and no account to manage.
- A homelab operator who needs the same tool on Linux, macOS, Windows and a NAS, writing to the same repository format everywhere.
- Anyone who wants append-only push backups: rest-server with
--append-onlymeans a compromised client cannot delete its own history. - People who already use rclone for transport and want real deduplicated snapshots on top of it via the
rclone:backend.
Look elsewhere if
- You want a GUI, a dashboard or a schedule you can click. restic ships none of that, and the third-party wrappers are yours to maintain.
- Your repository will be multi-terabyte and your backup host has under 4 GB of RAM:
pruneis the operation that will kill you, not the backup. - You need the backup tool itself to enforce retention immutably. restic relies on the backend (object lock, append-only rest-server) for that.
What running it actually looks like#
One static Go binary, no daemon, no listening port. You run it from cron or a systemd timer with RESTIC_REPOSITORY and RESTIC_PASSWORD_FILE in the environment and everything else as flags. restic init runs once against the target and writes a config file plus a keys/ entry; nothing else has to exist first. Backends are compiled in: local path, SFTP, REST, S3, Azure, Google Cloud Storage, Backblaze B2, and anything rclone speaks via the rclone: prefix. For push backups from machines that should not hold delete rights, run the separate rest-server (listens on 8000) with --append-only. Official images are restic/restic and ghcr.io/restic/restic, but most people run the host binary. Upgrading is replacing the file; newer restic reads older repositories, so upgrades do not break restores.
Resource profile#
- Memory
- 100 MB idle, around 800 MB in ordinary use. There is no daemon, so these are figures during a run. Memory is dominated by the repository index held in RAM, which scales with blob count, not with how much you are backing up today. Treat both numbers as estimates: a few hundred GB of repo is comfortable in under 1 GB, multi-TB repos with tens of millions of blobs need several GB for `prune`.
- CPU and acceleration
- Chunking and SHA-256 hashing saturate whatever cores you give it during a backup; `--compression max` roughly doubles CPU per byte. Limit with `GOMAXPROCS` if the backup is competing with a live service.
- Storage growth
- Deduplicated and compressed, so the repository grows with genuinely new data plus retained snapshot metadata. Pack files default to 16 MiB; temp space needed is pack size times backend connections plus one.
- Operational load
- 2 of 5, Light. One binary on a timer, no service to keep alive, upgrades are a file replacement. The ongoing attention is the maintenance loop: `forget`, `prune`, periodic `check --read-data-subset`, and clearing stale locks when a run gets killed.
Figures describe a small single-household install and are the working assumptions behind our stack planner. Your numbers will differ with library size, user count and hardware. See methodology.
Data and backup surface#
The repository is the backup, so integrity is the whole question. restic check verifies the index, decodes every tree, and confirms each referenced pack file exists at the expected size. It never reads pack contents, so it cannot see bit rot. Only restic check --read-data does, by downloading and re-hashing everything; --read-data-subset=1/10 monthly covers the repository over ten runs at a tenth of the egress. In practice repos are damaged by backends that silently drop or truncate objects, not by restic. Restore throughput is bounded by the backend, so rehearse it: restore one directory to /tmp and time it. Lose the password and the repository is unrecoverable, because the master key exists only wrapped inside keys/. Add a second password with restic key add and store it offline.
Derived backup shape
Mixed. Stop the service, copy its data directory, restart. Check upstream docs for a supported export command first.
Traps and surprises#
prune holds the whole index in RAM
restic loads the repository index into memory, and prune is the peak. Users with terabyte-scale repositories and millions of blobs report needing many gigabytes, well past what a small VPS has. Symptoms are the process being OOM-killed halfway through. Mitigate by pruning on a machine with real RAM, running forget frequently so the pruned set stays small, and using --max-repack-size to bound the work per run.
A killed run leaves an exclusive lock
restic takes a lock for every operation and an exclusive one for prune. If the process is killed, the host sleeps or the network stalls, the lock file stays and the next run aborts. restic unlock removes stale locks and --retry-lock 5m (0.16.0 and later) waits instead of failing. Never wire unlock unconditionally into a script that also runs prune, or you will let two prunes overlap.
Upgrading to repo v2 does not compress old data
migrate upgrade_repo_v2 only flips the format. Existing pack files stay uncompressed and only new backups get compressed, so your repository stays the same size for months. prune --repack-uncompressed fixes it but rewrites every pack, which means downloading and re-uploading the entire repository. On a remote bucket that is a real egress and time bill, so schedule it rather than discovering it.
forget without prune frees nothing
restic forget only removes snapshot references. Space is reclaimed by prune, and until it runs your storage bill does not move. Worse, forget applied without --host or --tag evaluates the retention policy across every snapshot in the repository, so a policy meant for one machine can delete another machine's history. Always scope the policy and always run forget --dry-run first when you change it.
The password is the only key, and it is not escrowed
restic wraps the repository master key with your passphrase and stores the wrapped copy in keys/. There is no recovery path, no vendor and no backdoor. If the passphrase lives only in the environment file of the machine you are backing up, then losing that machine loses the backup too. Run restic key add to create a second passphrase and keep it somewhere the primary host cannot reach.
Specifications#
- Category
- Backup and object storage
- Licence
- BSD-2-Clause (Permissive)
- Written in
- Go
- First release
- 2015
- Maturity
- Mature
- Datastore
- Its own content-addressed repository (files in a directory or bucket), no database service
- Default ports
- none
- Ships as
- native binary, distro package, docker
- arm64 builds
- Yes
- Identity
- Not applicable. No accounts and no web interface. Access control is whatever the storage backend enforces, plus the repository password.
- Replaces
- Backblaze Personal Backup, CrashPlan, Arq, Carbonite
- Project site
- restic.net
- Source
- github.com/restic/restic
- Documentation
- restic.readthedocs.io/en/stable
Alternatives to restic#
Everything else in backup and object storage, closest in operational weight first.
| Tool | Ops load | Idle RAM | Licence |
|---|---|---|---|
| BorgBackup | 2, Light | 80 MB | BSD-3-Clause |
| Kopia | 2, Light | 200 MB | Apache-2.0 |
| rclone | 2, Light | 40 MB | MIT |
| Duplicati | 3, Moderate | 200 MB | MIT |
| Garage | 3, Moderate | 150 MB | AGPL-3.0-only |
| MinIO | 4, Heavy | 250 MB | AGPL-3.0 (repository archived) |
Where restic comes up elsewhere#
Head to head
Migration guides
Guides
Research
Sources#
Facts on this page were checked against the project's own material. Where a number is our own estimate rather than a published figure, the text says so.
- restic 0.19.1 release announcement
- Docs, preparing a new repository (default repository version)
- Docs, working with repositories (upgrade_repo_v2, repack-uncompressed)
- Docs, tuning parameters (pack size, compression modes)
- restic 0.16.0 release notes (--retry-lock, lock refresh fixes)
- Licence file, BSD 2-Clause
Published . Last reviewed . Found something out of date? Tell us and we will fix it and log the change.