Backups & restore
A backup is a consistent snapshot of the main database — VACUUM INTO
on SQLite, pg_dump --format=custom on Postgres — streamed straight
into a ZIP and then into storage (local or S3) without ever buffering
the whole archive in memory — verified on a 1.6 GB SQLite database
peaking at ~330 MB RSS. The dashboard’s Backups page can trigger,
list, download, and restore a backup on either backend. One conformance
test against the real PocketBase SDK suite is skipped specifically
because it restarts the server mid-run to exercise restore, which would
kill the test harness itself — see
KNOWN_DIVERGENCES.md.
Postgres requirements
Section titled “Postgres requirements”Postgres backup/restore shells out to the real pg_dump/pg_restore
binaries — Cratebase itself has no Postgres dump/restore logic built
in. That means:
- The PostgreSQL client tools must be installed and on
PATH(or pointed at explicitly viaCB_PG_DUMP_PATH/CB_PG_RESTORE_PATH— see.env.example). The official Docker image already includes them (postgresql-clientin the runtime stage) — about 13 MB downloaded, ~68 MB unpacked (mostlyperl, a dependency of its wrapper scripts, not ofpg_dump/pg_restorethemselves). - Their major version should be
>=the Postgres server’s.pg_dumpcan read an older server, but restoring a newer server’s dump with an olderpg_restoreis unsupported by Postgres itself and can fail in confusing ways. If more than one Postgres version’s client tools are installed, useCB_PG_DUMP_PATH/CB_PG_RESTORE_PATHto pin the right one. - Connection details never touch the process’s command line. Host,
port, user, password, and
sslmodeall travel as environment variables (PGHOST/PGPORT/PGUSER/PGPASSWORD/PGSSLMODE) to the child process, so a password never leaks intops//proc/<pid>/cmdlineon a shared machine. - A missing
pg_dump/pg_restorefails clearly. Both a manual backup andsettings.backups.cronreport a specific, actionable error naming the missing binary and the override env var, rather than a generic “unsupported” message. - Restoring restarts the process, same as SQLite — even though
pg_restoreruns against the live connection rather than swapping a file, every schema/settings cache loaded at boot still needs to be rebuilt from what the restore just wrote, and re-exec is the same mechanism SQLite already needs for its own reasons. - A backup only restores onto the same engine it was taken from.
Restoring a SQLite archive (
data.db) onto a Postgres deployment, or a Postgres archive (data.pgdump) onto SQLite, is rejected with a clear400rather than attempted.
Scheduled backups
Section titled “Scheduled backups”settings.backups.cron runs create_scheduled on a schedule and keeps
only the newest cronMaxKeep archives. A failure there used to be only
a tracing::error! line — invisible unless someone was already tailing
logs. It’s now also recorded:
- as an
_audit_logrow (backup.scheduled_failed) with the error message, so it shows up alongside every other consequential superuser-visible event; and - as the last-scheduled-backup status returned by
GET /api/backups/storage-info(time, ok/error, message), which the dashboard’s Backups page renders as a badge next to the storage location.