rsync is one of the most useful programs ever written. It is on every machine you will ever touch, it moves files over SSH with a delta algorithm that was clever in 1996 and is still clever now, and for copying data from A to B it has no real competition.
It is also, on its own, not a backup system — and the gap is not about features anyone forgot to add. rsync synchronises directories. Backup is a different job that happens to involve copying files, in the same way that accounting is a different job that happens to involve arithmetic.
This is an honest comparison, including the cases where rsync is still what you should use.
The script almost everyone writes
rsync -av --delete /var/www/ backup-server:/backups/www/
This is a good command. It is also, as a backup strategy, one deletion away from useless — and the reason is --delete.
Without --delete, your backup grows forever and never reflects deletions. Files removed from production three years ago are still there, you are paying to store them, and you can never answer "what did this directory look like in March?"
With --delete, deletions propagate. Someone runs rm -rf on production at 4pm, the sync runs at 2am, and the backup faithfully deletes the same files. You now have two identical copies of the disaster.
That is the trap, and it is inherent: rsync's job is to make the destination match the source. When the source is wrong, a correct rsync makes the destination wrong too. Backup systems are built on the opposite premise — that the source might be wrong, and history is what saves you.
The honest counter: --link-dest
Experienced rsync users will point out you can build versioning with hard links:
rsync -av --delete \
--link-dest=/backups/www/2026-08-20 \
/var/www/ /backups/www/2026-08-21/
Unchanged files become hard links to yesterday's copy, so each dated directory looks like a full backup while only consuming space for what changed. This is genuinely clever, it is what rsnapshot and Time Machine are built on, and it works.
It also has real limits worth knowing before you build on it:
- Deduplication is whole-file only. Change one byte in a 4 GB database dump and you store 4 GB again. Content-defined chunking stores the changed region.
- Hard links need one filesystem. Your snapshots and your live backup are on the same volume, which is one disk failure away from all of them.
- No integrity verification. Nothing detects bit rot; a corrupted file is silently linked forward into every future snapshot.
- Retention is your problem. You write the script that deletes old directories, and you get to be the one who gets the date arithmetic wrong.
- No encryption at rest. rsync encrypts in transit over SSH. On the destination disk, everything is plaintext.
So: --link-dest gets you versioning. It does not get you a backup system, and the difference is mostly in the things that only matter on the day you need them.
Side by side
| rsync | Backup Data | |
|---|---|---|
| Versioned history | Manual, via --link-dest | Every run is a snapshot |
| Deduplication | Whole file | Content-defined chunks (FastCDC) |
| Encryption at rest | None — you add LUKS or nothing | AES-256-GCM, client-side |
| Integrity on restore | None | Checksums verified before reassembly |
| Retention policy | A script you write | pruneSnapshots, with dry-run |
| Deletion protection | --delete propagates deletions | Snapshots are immutable |
| Destination | A box you own and maintain | Managed |
| Cost | Free + your server + your time | Free to 5 GB, then from $12/mo |
| Restore | rsync the other way | client.restore(...) |
| Works offline / air-gapped | Yes | No, needs network |
| Available everywhere | Yes, universally | Node or Go SDK |
What rsync is genuinely better at
This is not a list of consolation prizes. There are jobs where rsync is the correct tool and reaching for anything else is overengineering.
One-off migrations. Moving 200 GB between two servers you control. rsync, resumable, done.
Keeping a live mirror in sync. A read replica of a static asset directory, updated every five minutes for serving rather than for recovery.
Air-gapped or offline destinations. rsync to a USB drive or a machine on an isolated network works with no service dependency at all.
Environments where you cannot install anything. rsync is already there. On a locked-down host, that matters more than any feature comparison.
Feeding another backup system. These are not mutually exclusive, and the combination is often right — rsync to stage files locally, then snapshot the staging directory. Our S3 guide uses exactly this shape with aws s3 sync.
What the difference looks like in practice
The scenario that separates them is not exotic. It is the ordinary one.
A bad migration corrupts a table on Tuesday. Nobody notices until Friday.
With rsync mirroring nightly: the corruption was faithfully copied Tuesday night, and again Wednesday, Thursday, and Friday. Your backup is a perfect copy of the broken data. Unless you built --link-dest snapshots and kept more than three days of them, there is nothing to go back to.
With versioned snapshots: Monday's snapshot is untouched and immutable. You restore it into a scratch database, confirm the table is intact, and pull the rows forward.
That is the entire argument. Not speed, not compression, not cost — the ability to go back to before the problem started, which requires history that the current state cannot overwrite.
If you are moving from rsync
The migration is smaller than expected, because your existing script already produces the hard part: a directory that reflects current state.
# Keep whatever you already do to assemble the data.
rsync -av --delete /var/www/ ./staging/www/
pg_dump --format=custom --file=./staging/db/app.dump app_db
import { BackupClient } from "@lighthouse-web3/baas-js-sdk";
const client = new BackupClient({
apiKey: process.env.LH_API_KEY,
workspaceId: process.env.LH_WORKSPACE_ID,
});
const snapshot = await client.backup(["./staging"], {
description: "nightly",
tags: { type: "files", host: "web-01" },
encryption: {
keyfilePath: "/secure/lh.keyfile",
passphrase: process.env.LH_KEYFILE_PASSPHRASE,
},
});
Note that --delete is now the right choice on the staging mirror, where it was dangerous before. Each upload is an immutable point-in-time snapshot, so history lives in the snapshots rather than in an ever-growing local directory. The mirror should track the source exactly.
You hold the encryption keys — lose the keyfile and passphrase and the data is unrecoverable, with no server-side reset.
The honest summary
If you need to copy files from one place to another, use rsync. It is excellent, it is free, and nothing here replaces it.
If you need to answer "what did this look like last Monday, and can I prove it restores" — that is a different question, and rsync was never built to answer it. The --link-dest pattern gets you partway and stops short of encryption, integrity verification, chunk-level dedupe, and a destination you do not have to maintain.
Plenty of good setups use both: rsync to gather, snapshots to keep.
Start with the free tier: backupdata.io has 5 GB free, no card, and the 10-minute quickstart gets you to a first verified snapshot today.