Knowledge base · Restores
Restoring a backup into a new project
How a one-click restore works, why the target must be empty, what to do about Postgres versions and Storage, and what the report tells you.
Restores write your backup into a database you designate. VaultKeep never restores over the project it backed up: the target must be empty, on purpose.
Before you start
- Create a new, empty Supabase project, or any other empty PostgreSQL database you control (RDS, Neon, self-hosted). Its Postgres major version must be the same as, or newer than, the version the backup came from; the version is shown on the backup. Storage can only be restored into a Supabase project.
- Copy its connection string (direct or session pooler, port 5432).
- If you want Storage restored as well, you also need the new project's ref and S3 access keys, so buckets and files can be recreated.
Steps
- Open the original project → Backups, pick a database backup, click Restore. A database restore is the whole project: schema and data, plus Storage if you opt in.
- Paste the target connection string. To restore Storage too, switch on Also restore storage, pick the storage sync to use (it defaults to the one taken with that database backup) and enter the ref + S3 keys. Leave it off to restore the database alone.
- Type the project name to confirm. This is the two-step confirmation; there is no way to skip it.
- Watch progress under Restores. You are emailed when it finishes.
The target credentials are used once and destroyed as soon as the restore ends.
What happens
- Preflight: the runner connects to the target and counts user tables. If there are any, the restore aborts with "the destination already contains N user tables" and nothing is written. This is the control that makes restoring over production impossible.
- Integrity: the artifact's hashes are checked before anything is restored.
- Platform stand-ins (non-Supabase destinations only): a schema backed up from Supabase references objects the platform provides, such as
auth.uid()in policies, theanonandauthenticatedroles, and extension functions likeuuid_generate_v4(). When the destination is not a Supabase project, VaultKeep creates minimal stand-ins for them first, exactly as the weekly verifier does for its throwaway cluster, and lists what it created in theplatform_shimscheck. Extensions the server does not offer are named there too; statements that depend on them show up aspg_restoreerrors. - Database: a full
pg_restore(--no-owner, parallel jobs), skipping Supabase-managed schemas such asauth,storageandextensions, which a Supabase destination already provides. - Storage (when included): after the database is in, buckets are created with the same names and every object is streamed back decrypted with the key recorded for it in the manifest. If this phase fails, the report says so; the database restore is not rolled back.
- Report: the same checks as a verification run against the restored database (table and row counts, content hashes, sequences, indexes and constraints versus the manifest), plus the count of restored objects for Storage. The report is stored with the restore and shown in the app.
Business (managed) backups: the whole project
Backups taken on the Business plan also hold custom roles, Auth users (with their password hashes), bucket settings and Storage policies, triggers on auth tables, cron jobs, deployed Edge Functions, Auth and API settings, and a bundle of each GitHub repository added to the project (web app, mobile app, desktop app: as many as you need). A restore into a Supabase project replays them in order: roles and Auth rows first, then the schema, then triggers, policies and cron jobs. Into plain PostgreSQL the Auth and Storage parts are created as real tables too, so the restore verifies foreign keys to auth.users.
Two optional fields on the credentials step cover what lives outside the database:
- Supabase access token: a personal access token that can manage the destination project. With it, the backup's Edge Functions, Auth settings (site URL, redirect URLs, providers, email templates, rate limits, MFA) and API settings are applied to the new project. Secret values are never stored in backups; the
secrets_to_reentercheck lists every Edge Function secret and Auth secret to set by hand. - Destination GitHub repositories: for each repository in the backup you want back, an empty repository to push it into, plus one token that can push to all of them. Every branch and tag is pushed; a destination that already has commits is refused. Repositories you leave blank are skipped and listed in the report.
After the restore
- Re-point your application at the new project (URL, API keys), update OAuth callback URLs at your providers, and set the secrets listed in the report. Users keep their passwords but sign in again: sessions are not restored.
- On Pro and Team, rows in
auth.usersare not part of the backup, because the new project manages that schema. If you need users migrated, export them withsupabase db dump --data-only --schema authfrom the original project while it still exists. - Check a few signed Storage URLs and your most important tables before announcing it done.
If a restore fails, the target is left as it is; fix the cause shown in the report and start a new restore.
Storage-only restores
Clicking Restore on a Storage backup restores buckets and files only. It creates no tables and no rows, so the new project's public schema stays empty. Use it when the database is already in place (for example after a database-only restore) and you want to bring the files across afterwards.
Still stuck? Email support@vaultkeep.dev with your project name (never your connection string) and we'll take a look.