Differential Backups
A differential backup captures only the files that have changed since the most recent full backup for the same profile, instead of re-archiving the entire site. This makes routine backups smaller and faster while still allowing a restore from a full + differential pair.
Differential logic applies to the file portion of a backup only. The database is always dumped in full on every run (differential backups still contain a complete
database.sql).
Enabling it
Set the profile's backup_type to differential (#__mokosuitebackup_profiles.backup_type). The other backup types are full, database, and files.
How it works
Change detection is handled by DifferentialScanner (com_mokosuitebackup/src/Engine/DifferentialScanner.php) using a stored file manifest.
1. Manifests on full backups
When a full backup runs, after scanning the filesystem BackupEngine builds a JSON manifest of every included file and stores it on the backup record (#__mokosuitebackup_records.manifest). The manifest maps each relative path to its size and modification time:
{
"index.php": { "size": 1234, "mtime": 1717350000 },
"templates/site/x.css": { "size": 512, "mtime": 1717340000 }
}
2. Finding the base
When a differential backup runs, BackupEngine::loadBaseManifest() loads the manifest from the most recent full backup for that profile whose status is complete or warning and whose manifest is non-empty (newest backupstart first).
- No base found — if there is no prior full backup with a manifest, the differential falls back to a full backup: it archives every file and builds a fresh manifest for future differentials. The log records
No base full backup found — running full backup instead.
3. Comparing files
DifferentialScanner::getChangedFiles() walks the current file list from FileScanner and keeps a file when:
- it is new (not present in the base manifest), or
- it is modified — its current
sizeormtimediffers from the base manifest entry.
Unchanged files (same path, size, and mtime) are skipped. Only the changed/new set is added to the archive. The log records, e.g., Differential: 37 changed files out of 12048 total.
4. Linking to the base
Differential records reference their base full backup via #__mokosuitebackup_records.base_record_id, so a restore knows which full backup to combine with the differential.
Restore model
Restoring a point-in-time differential means restoring its base full backup first, then overlaying the differential's changed files on top. Because the manifest tracks size/mtime rather than deletions, differentials capture new and modified files; the base full backup provides the complete baseline.
Configuration summary
| Setting | Where | Effect |
|---|---|---|
backup_type = differential |
Profile | Enables differential file capture for the profile |
manifest |
Record (_records) |
JSON path→size/mtime map; written on full backups, read by differentials |
base_record_id |
Record (_records) |
Links a differential to the full backup it is based on |
Notes & limitations
- Change detection uses size and modification time, not content hashing — a file whose contents change without altering size or mtime would not be detected as changed. This is a deliberate performance trade-off.
- A differential always contains a full database dump; only files are differential.
- Keep the base full backup available: pruning it (via retention) leaves its differentials without a baseline. Plan retention so a full backup outlives the differentials that depend on it.
- Exclusions (
exclude_dirs,exclude_files) apply the same way on full and differential runs, so the compared file universe is consistent.