Comparisons

Incremental vs differential backup: restore time, storage and chain risk

Incremental vs differential backup: what each copies, a week worked through, a GNU tar test of restore chains, snapshots and the 3-2-1 rule for servers.

Published ~10 min read
On this page

Short answer: an incremental backup copies only what changed since the last backup of any kind; a differential backup copies everything that changed since the last full backup. Incrementals are smaller and quicker to take, but a restore needs the full plus every incremental in order. Differentials grow each day but restore from just two pieces.

Below: the three types side by side, a week of backups worked through, a GNU tar run that shows the difference on real files (Debian 12, GNU tar 1.34, rsync 3.2.7, run for this article), and how snapshots, deduplicating tools and the 3-2-1 rule fit around it.

Full vs incremental vs differential

FullIncrementalDifferential
CopiesEverythingChanges since the last backup of any typeChanges since the last full backup
Backup timeLongestShortest, and about the same every dayGrows every day until the next full
Storage per runThe whole data setSmallestGrows every day until the next full
A restore needsThat one backupThe full plus every incremental since, in orderThe full plus the newest differential
Restore effortSimplestMost pieces to fetch and applyTwo pieces
If one piece is lost or damagedOnly that backup is goneEvery later point in the chain is incompleteOnly that day is gone; other days still restore
Typical scheduleWeekly or monthlyDaily or hourly between fullsDaily between fulls

Both incremental and differential backups start from a full backup, and both save time and space against taking a full every night. The difference is the reference point. An incremental compares against the previous backup, whatever it was. A differential always compares against the last full, so each one contains the previous differential’s changes again plus whatever happened since. Lose the full, and everything built on it is gone with either method, which is why the full deserves the best-protected copy.

One week, worked through

Take a 100 GB server with a full backup on Sunday, and assume 5 GB of different data changes every day, which is the worst case for differentials:

DayIncremental that dayDifferential that dayRestore to this day needs
Sunday100 GB full100 GB fullThe full alone
Monday5 GB5 GBFull + Mon (either way)
Tuesday5 GB10 GBFull + Mon + Tue, or full + Tue diff
Wednesday5 GB15 GBFull + 3 incrementals, or full + Wed diff
Thursday5 GB20 GBFull + 4 incrementals, or full + Thu diff
Friday5 GB25 GBFull + 5 incrementals, or full + Fri diff
Saturday5 GB30 GBFull + 6 incrementals, or full + Sat diff
Week total130 GB205 GB

Two things in that table are often misread. First, with different data changing each day, a Saturday restore reads the same 130 GB either way: the full, plus 30 GB of changes, spread over six incrementals or held in one differential. The differential wins on the number of pieces that all have to be present and readable, not on volume. Second, if the same files change every day (a database file, a busy log), the Saturday differential stays near 5 GB, so differentials cost far less than the worst case above. Real servers land somewhere between.

Trying it: incremental and differential backups with GNU tar

GNU tar does both through one option, --listed-incremental, which keeps a snapshot file of what it saw last time. Keep updating one snapshot file and every run is incremental; start each run from a fresh copy of the full backup’s snapshot file and every run is differential. The GNU tar manual describes exactly this copy trick for “level 1” backups.

Linux · GNU tar
# Sunday: the full backup (level 0); tar records what it saw in snap.full
tar --create --file=full-sun.tar --listed-incremental=snap.full site

# incremental: one snapshot file, updated by every run
cp snap.full snap.inc                         # once, after the full
tar --create --file=inc-mon.tar --listed-incremental=snap.inc site
tar --create --file=inc-tue.tar --listed-incremental=snap.inc site

# differential: a fresh copy of the full's snapshot file before every run
cp snap.full snap.diff
tar --create --file=diff-mon.tar --listed-incremental=snap.diff site
cp snap.full snap.diff
tar --create --file=diff-tue.tar --listed-incremental=snap.diff site

Our test directory held twenty files of 100 KB. On Monday two files changed and a 50 KB file was added; on Tuesday one other file changed and another 50 KB file was added; on Wednesday one file was deleted and one more changed. The archive sizes, in bytes:

Output (ls -l, sizes in bytes)
2068480  full-sun.tar
 266240  inc-mon.tar     266240  diff-mon.tar
 163840  inc-tue.tar     419840  diff-tue.tar
 112640  inc-wed.tar     522240  diff-wed.tar

The incrementals shrink to that day’s changes; the differentials keep growing, because Wednesday’s still carries Monday’s and Tuesday’s files. tar -tf diff-wed.tar lists all six changed or new files, tar -tf inc-wed.tar only the one changed that day. To restore, extract in order into an empty directory with --listed-incremental=/dev/null, which also makes tar replay deletions:

Linux · GNU tar
# incremental: the full, then every incremental in order
for a in full-sun inc-mon inc-tue inc-wed; do
  tar --extract --listed-incremental=/dev/null --file="$a.tar"
done

# differential: the full, then only the newest differential
for a in full-sun diff-wed; do
  tar --extract --listed-incremental=/dev/null --file="$a.tar"
done

Both restores matched the live directory exactly (diff -r printed nothing), and the file deleted on Wednesday was gone in both. Then we restored the incremental chain again with Tuesday’s archive left out. tar did not print a single warning, and diff -r found one file back at its Sunday version and Tuesday’s new file missing. That is the chain risk in practice: a missing incremental does not fail loudly, it silently rolls part of your data back.

rsync --link-dest: incremental to store, full to restore

rsync --link-dest takes a different route. Every run produces a folder that looks like a complete copy, but unchanged files are hard links to the previous folder, so only changed files take new space. In our run, the first snapshot used 2.0 MB and the next one, after one 100 KB file changed, 104 KB (as counted by du -sh over both). Deleting the older folder left the newer one complete (diff -r against the source was still empty), because a hard-linked file lives on as long as one name points at it. There is no chain to break: each folder restores on its own. The full commands are in the rsync guide.

Deduplicating tools: restic and Borg

restic and Borg split files into chunks, store each chunk once, and record every backup as a list of chunks. Every snapshot is a complete point in time that restores on its own, yet each run only uploads chunks the repository does not already have. The full/incremental/differential question mostly disappears; what remains is the health of the repository, because a damaged chunk can affect every snapshot that uses it. restic always encrypts, Borg does with the mode chosen at init (repokey below), and both forget old snapshots by a retention policy:

restic (Debian 12 packages 0.14.0)
restic -r sftp:backup@203.0.113.20:/srv/restic/web1 init
restic -r sftp:backup@203.0.113.20:/srv/restic/web1 backup /etc /srv /var/backups/db
restic -r sftp:backup@203.0.113.20:/srv/restic/web1 forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic -r sftp:backup@203.0.113.20:/srv/restic/web1 check
Borg 1.x (Debian 12 packages 1.2.4)
borg init --encryption=repokey ssh://backup@203.0.113.20/srv/borg/web1
borg create --stats ssh://backup@203.0.113.20/srv/borg/web1::'{hostname}-{now}' /etc /srv
borg prune --keep-daily 7 --keep-weekly 4 --keep-monthly 6 ssh://backup@203.0.113.20/srv/borg/web1
borg compact ssh://backup@203.0.113.20/srv/borg/web1
borg check ssh://backup@203.0.113.20/srv/borg/web1

These are written from the restic and Borg documentation, not run here. Since Borg 1.2, prune only marks space as free and compact gives it back. Borg 2 changes the command syntax, so check borg --version before copying commands. Keep the restic password and an export of the Borg key (borg key export) somewhere other than the server: without them the backup cannot be read.

Synthetic full, forever incremental and reverse incremental

  • Synthetic full: the backup system builds a new full backup on the backup storage from the last full and the incrementals since, without reading the source again. The production server only ever sends incrementals, and restores still start from a recent full.
  • Forever incremental: one full at the start, then only incrementals, with old ones merged into the base as they age out. Deduplicating tools behave like this by design.
  • Reverse incremental: the newest backup is always kept as a full, and older points are stored as the differences needed to step back. The most likely restore, the latest one, is the quickest.

Differential and incremental backups in databases

Databases use the same words. In Microsoft SQL Server, a differential backup holds the changes since the last full backup, its “differential base”, and transaction log backups fill the gaps between differentials (per Microsoft’s documentation; not run here):

SQL Server (T-SQL)
BACKUP DATABASE Shop TO DISK = N'D:\Backup\Shop_full.bak' WITH INIT;
BACKUP DATABASE Shop TO DISK = N'D:\Backup\Shop_diff.bak' WITH DIFFERENTIAL, INIT;

-- restore: the full without recovery, then the newest differential with recovery
RESTORE DATABASE Shop FROM DISK = N'D:\Backup\Shop_full.bak' WITH NORECOVERY, REPLACE;
RESTORE DATABASE Shop FROM DISK = N'D:\Backup\Shop_diff.bak' WITH RECOVERY;

A full backup taken WITH COPY_ONLY does not become the base for later differentials, which is how you take an extra full without breaking the schedule. PostgreSQL added incremental base backups in version 17 (pg_basebackup --incremental, merged back into a full with pg_combinebackup, and summarize_wal switched on); Debian 12 ships PostgreSQL 15, which has neither. For most small servers, a nightly pg_dump or mysqldump --single-transaction into a file that the file-level backup then picks up is simpler and restores anywhere.

Snapshots are not the same as backups

A snapshot freezes a whole disk at one moment, usually by copy-on-write inside the same storage system, so it is quick to take and quick to roll back. That makes it ideal right before an upgrade. It is not an independent copy: it lives with the disk it protects, restoring it rolls back everything at once, and a database caught mid-write is only as safe as its crash recovery. The block storage guide explains the mechanics. Use snapshots for fast rollbacks and backups for getting data back after anything worse.

The 3-2-1 rule, and who can delete your backups

  • 3 copies of the data: the live one and two backups.
  • 2 different kinds of storage, so one failure mode cannot take both.
  • 1 copy offsite, in another building or with another provider.

The modern addition is one copy that the server itself cannot delete. If the production server holds credentials that can erase its backups, so does anyone who gets root on it. Either let the backup machine pull from production, or make the repository append-only: Borg’s documentation shows a forced command in the backup user’s authorized_keys for that:

~backup/.ssh/authorized_keys on the backup server
command="borg serve --append-only --restrict-to-path /srv/borg/web1",restrict ssh-ed25519 AAAA... root@web1

With that key, the production server can add backups but not remove them, so a prune sent through it frees no space. Run prune and compact on the backup server itself, against the local path /srv/borg/web1, after checking that the archives in the repository look as expected.

Then test a restore on a schedule, into a scratch directory or onto a spare server. A backup that has never been restored is a hope, not a backup, and the tar test above shows how quietly an incomplete chain can fail.

A schedule that works for most small servers

  • A provider snapshot before every upgrade or risky change.
  • Nightly database dumps to a file, kept for a few days on the server itself.
  • Nightly deduplicated backups (restic or Borg) to a second machine, keeping 7 daily, 4 weekly and 6 monthly snapshots, run from cron or a systemd timer.
  • A weekly copy of that repository, or a second repository, with another provider or at home.
  • A restore test every month.

Backups on a VMHeaven VPS

Every KVM VPS has a Backups tab in the panel. A backup there is a snapshot of the whole disk, taken while the server keeps running, either by hand or automatically on a daily, weekly or monthly schedule. Scheduled runs rotate through a fixed number of slots and replace the oldest unprotected backup only once the new one has finished; a backup you mark as protected is never replaced. Snapshots taken before a reinstall are kept.

Restoring one overwrites the current disk, and everything written since that snapshot is lost. That makes the panel backups a rollback tool for the whole server, not a way to fetch one deleted file from last Tuesday. Pair them with file-level backups to somewhere else. A Storage VPS makes a good backup target, with disk added from the panel in 15 GB blocks as the repository grows, and a further copy outside your VMHeaven account keeps the “1” in 3-2-1 honest. A backup you can restore onto a fresh machine is also your plan for moving to a new server.

Frequently asked

What is the difference between incremental and differential backups?

An incremental backup copies what changed since the last backup of any kind, so each one is small. A differential backup copies everything that changed since the last full backup, so it grows every day until the next full. Restoring incrementals needs the full plus every incremental in order; restoring a differential needs the full plus the newest differential.

Which restores faster, incremental or differential?

Usually differential, because only two pieces are needed: the last full and the newest differential. An incremental restore has to apply every incremental since the full, in order. If different data changes every day, both restores read about the same volume; the differential's advantage is fewer pieces that must all be present and intact.

What is a differential backup?

A backup of every file or block that changed since the last full backup. Each new differential replaces the previous one for restore purposes, so a restore needs just the full and the most recent differential. In Microsoft SQL Server, the full backup a differential refers to is called its differential base.

Is a VPS snapshot a backup?

Not on its own. A snapshot is a point-in-time state of the whole disk, ideal for rolling back after a failed upgrade, but restoring it replaces everything written since, and it is kept by the same platform as the server. Keep file-level backups on another machine as well, and one copy with another provider or at home.

Related articles

All comparisons