Backups
By the end of this page you will have taken a base backup of a ScramDB instance, verified it landed correctly, and (optionally) configured your instance so that backup location also powers branch-from-timestamp.
What a base backup isβ
A base backup is a cold, consistent snapshot of a stopped instance's data directory, plus a manifest recording exactly where in the write-ahead log (WAL) the snapshot was taken. scramdb backup opens the instance the same way the server itself starts up (full recovery and reconciliation, no shortcuts), triggers a checkpoint to get a clean, well-defined WAL position, then streams every file in the data directory except the live wal/ subtree to your chosen destination. The manifest is written last, so a backup interrupted partway through leaves either a complete backup or an incomplete one with no manifest, never a false-success partial backup that restore would accept.
This is a cold backupβ
scramdb backup is explicitly offline. It refuses to run if the target instance's data directory is currently locked by a running scramdb server, with an error that says exactly that:
cannot back up '<dir>': the storage directory is locked by a running scramdb server.
This is a cold backup tool ... stop the server first, or back up from a stopped replica.
Online (hot) backup against a live, traffic-serving server is a separate capability, not built into this tool today. In practice this means one of two things:
- Stop the server for the duration of the backup, then start it again, or
- Point
scramdb backupat a stopped replica or a copy of the data directory that is not currently held by a running instance.
Take a backupβ
-
Stop the server (or make sure you are pointing at a stopped copy of the data). If you are running the Docker image:
docker stop scramdb -
Run
scramdb backup, pointing--configat the config file whosestorage.basedirnames the instance you want to back up, and--outat a destination:scramdb backup --config /etc/scramdb/config.toml --out file:///var/lib/scramdb/backups/2026-08-02--outaccepts a local directory path or an object storage URL:s3://bucket/prefix,gs://bucket/prefix,az://account/container/prefix, orfile:///abs/path. A bare string with no scheme is treated as a local filesystem path. -
Check the output. A successful backup logs a single summary line:
backup complete: N file(s), base_lsn=<LSN>, base_wal_file_id=<ID>, destination='file:///var/lib/scramdb/backups/2026-08-02'base_lsnis the exact WAL position the backup represents. Note it, or the timestamp you ran the backup at, you will want one of them if you ever restore or branch from this backup with an explicit target. -
Inspect what landed at the destination:
ls /var/lib/scramdb/backups/2026-08-02Expect a
manifest.jsonfile and adata/subdirectory holding the snapshotted tree. Ifmanifest.jsonis missing, the backup did not complete; do not trust thedata/contents. -
Restart the server if you stopped it for the backup:
docker start scramdb
If it fails: the most common cause is the storage-directory-locked error above, which means the instance is still running against that basedir. Stop it (or all containers/processes sharing that volume) and retry. A permissions or connectivity error against an object storage destination surfaces as a plain I/O error naming the destination; check your credentials and bucket/container name.
What's included, and what isn'tβ
Included: every file under the data directory except the live WAL subtree, this covers the catalog and all table data as of the checkpoint the backup took.
Not included: the live WAL segments. Those are handled separately, either from the local wal/ directory (bounded by your retention settings) or from the WAL archive, at restore time via --wal-source. See Restore for how the two come together.
The manifest also records a format version and a timeline identifier. Today ScramDB backups are single-timeline: a backup, its restores, and any branches taken from it all share one timeline, so there is no support yet for diverging restore paths that later need to be told apart.
Configure a backup location for branch-from-timestampβ
CREATE DATABASE ... FROM ... AT TIMESTAMP ... (see Branching) lets a running server fork a database as of a past moment, without you invoking scramdb backup and scramdb restore yourself. To make that work, tell the running server where to find its own base backup:
[storage.wal.backup]
destination = "file:///var/lib/scramdb/base-backup"
This is one configured location holding the current base backup, not a searchable registry of several dated backups. If you take a fresh backup to this destination, branch-from-timestamp and PITR-via-archive get that backup's coverage; picking automatically among multiple historical backups is not something ScramDB does today, so refresh the backup at this location on whatever cadence your recovery window requires.
To actually populate that location, run scramdb backup with --out pointed at the same destination:
scramdb backup --config /etc/scramdb/config.toml --out file:///var/lib/scramdb/base-backup
WAL archiving is the backup's companionβ
A base backup only gets you back to the moment the backup was taken. To restore or branch to a moment after that, ScramDB needs the WAL written since then. Without WAL archiving, only the WAL still sitting in the instance's local wal/ directory is available, and that is bounded by your retention settings, older segments get pruned. With archiving enabled, WAL is shipped continuously to a durable location that restore can pull from, extending how far forward you can replay from a given backup.
The shipped Docker image enables archiving by default. See Point-in-time recovery for the full [storage.wal.archive] and [storage.wal.retention] reference.
Nextβ
- Restore: rebuild a fresh instance from this backup.
- Point-in-time recovery: restore to an exact moment instead of the latest available point.
- Branching: use this backup to fork a database as of a past moment, on a live server.