# Backups and restore

> Status: Available. A backup is one complete, consistent image of one database. A restore creates a new database.

| | |
|---|---|
| **Works** | Whole-database backup while writes continue. Image verification. Scheduled backups with retention and restore drills. Restore into a new database. |
| **Differs** | A restore never overwrites the original. The restored database has a new name, a new ID and a new token. |
| **Missing** | Point-in-time restore. Incremental backups. Backups that skip idle databases. |
| **Operational impact** | A scheduled backup activates each database and copies it in full. |
| **Evidence** | Covered by the project's backup tests. How large a database fits in one backup window has not been measured. |

Put backups in a second bucket, ideally at a second provider. Losing the bucket loses everything since the last finished backup.

## Take a backup

```sh
image="s3:$PWD/backup.env#images/app/$(date -u +%Y%m%dT%H%M%SZ)"
gauntlet backup --source https://n1.example.net:7101/db/app --store "$image"
gauntlet verify-image --store "$image"
```

- Use a new prefix for every backup. A non-empty destination is refused.
- The database keeps serving writes while the backup runs.
- Keep the printed receipt.
- A backup that cannot finish copying in time fails cleanly. It never leaves a partial image marked ready.

## Schedule backups

`gauntlet backups` runs from cron on a backup host. It backs up every database on an interval, applies retention, and runs restore drills.

```sh
*/15 * * * *  gauntlet backups run   --config /etc/gauntlet/backups.json
30 3 * * *    gauntlet backups drill --config /etc/gauntlet/backups.json --cache-dir /srv/gauntlet-cache/drill
0 * * * *     gauntlet backups status --config /etc/gauntlet/backups.json >/dev/null
```

The defaults are a daily backup, keeping 7 images and 30 days.

## Restore

A restore creates a **new database with a new name, a new ID and a new token**.

1. Verify the image: `gauntlet verify-image --store "$image"`.
2. Make a working copy of the image if the original must stay an archive. Serving an image turns it into a live cluster.
3. Serve the copy on loopback with `gauntlet node`, wait for `/ready`, then run `gauntlet restore-database --store 's3:#gauntlet/beta' --name app-restored --source http://127.0.0.1:7201`.
4. Get the new token: `gauntlet admin token app-restored`.
5. Check the data, then point clients at the new name and token.

**Do a restore drill before you need one.** An image you have never restored is not yet a backup.

## Coming

- **Restore to a transaction ID** (P10.17): exact, one cut across shards, into a new identity.
- **Backups that skip unchanged databases** without waking them (P10.50).

See [branches and point-in-time recovery](https://gauntlet-db.stavros.xyz/docs/concepts/branches-and-recovery.md).

---
Source: https://gauntlet-db.stavros.xyz/docs/operations/backups
