Backups
See Deploy → Backups & restore for the snapshot mechanism behind these endpoints.
| Method & path | Summary |
|---|---|
GET /backups |
List archives, newest first |
POST /backups |
Take a fresh backup now |
POST /backups/upload |
Upload an existing archive |
GET /backups/storage-info |
Which store backups are written to |
GET /backups/{key} |
Download one archive |
DELETE /backups/{key} |
Delete one archive |
POST /backups/{key}/restore |
Restore from an archive |
POST /backups
Section titled “POST /backups”Body optional: { "name": "custom-name.zip" } — defaults to
PocketBase’s own pb_backup_YYYYMMDDHHMMSS.zip pattern. A ZIP of a
consistent snapshot of the main database (data.db on SQLite,
data.pgdump on Postgres — see
Deploy → Backups & restore for the
Postgres requirements), the auxiliary (logs) database, and the
local-disk storage tree when files aren’t on S3. 204 on success.
GET /backups/storage-info
Section titled “GET /backups/storage-info”{ "driver": "local", "location": "/app/data/backups", "lastScheduled": { "at": "2026-09-24 03:00:00.000Z", "ok": false, "message": "..." }}lastScheduled is only present once settings.backups.cron has fired
at least once, and message only on a failed run.
GET /backups/{key} — authenticated by query token, not bearer
Section titled “GET /backups/{key} — authenticated by query token, not bearer”GET /backups/pb_backup_20250115103000.zip?token=<file-token>Uses a superuser file token (from POST /files/token)
in the query string, not Authorization — the same reason ordinary
protected file downloads do: a browser <a download>/window.open
can’t set headers.
POST /backups/{key}/restore
Section titled “POST /backups/{key}/restore”Extracts and validates the archive, then — on SQLite — swaps the data
directory, or — on Postgres — runs pg_restore --clean --if-exists --single-transaction against the live database, and either way
re-execs the current binary with the same arguments. The process id
survives (a supervisor sees no crash), but every open connection is
dropped, and the swap/restore happens after this endpoint has
already answered 204. Restoring a SQLite archive onto Postgres (or
vice versa) is rejected with 400 before anything is touched. This is
the one conformance-suite test that’s permanently skipped rather than
run against a live server — see
Compatibility.