Supabase project down: get running from your own backup
Your project is stuck in RESTORE_FAILED or COMING_UP, reports
unhealthy, or sits behind a billing lock, and the support ticket has no date on it. This
guide moves your app to a new project from a backup you keep outside Supabase: the
database, the files in Storage, and the settings a dump does not carry. In our test the
database restore took 57 seconds. The settings in section 5 take longer.
It only works if the backup exists before the outage. If you have none yet, read the last section first, then set one up today with GitHub Actions or on SafeGrd.
1. Wait, or move
Moving costs you the settings work below and a cutover. Waiting costs you the outage. These are the cases where waiting has no end you can see, from threads in Supabase's GitHub Discussions between 22 September and 15 October 2026:
| What you see | Why the dashboard cannot fix it |
|---|---|
| “Something went wrong while restoring your project”, for days | “Restore to a new project” is refused while the project is offline, so the self-service path needs the project you cannot reach. One Pro project was down 72 hours this way. |
A restore to a new project stuck at COMING_UP | The new project waits on the same infrastructure team. One sat 11 hours with an empty cluster. |
| A paused Free project that will not resume | Free tickets have no response time. The resume can fail with “No compatible image exists” or fall back to paused after 15 minutes. |
| “User is banned” after a payment problem | You cannot sign in to the dashboard at all, so nothing in it helps. |
If one of these is yours and your users are waiting, start a new project now. You can still go back to the old one when it returns (section 7).
2. Create the new project
- Same region, if a contract or a customer requires your data to stay in it.
- Same PostgreSQL major version as the old project. The dashboard's backup list shows it after
PG:, if you can still sign in. - A new database password. Keep it in an environment variable, not your shell history.
Leave the new project empty. Do not run your migrations first: the restore creates the
tables in public, and fails on a table that already exists.
3. Restore the database
Run this from any machine with the CLI and your SafeGrd config:
--schema public recreates your tables and their rows.
--data-only-schema auth --data-only-schema storage loads your users and the
Storage file records into the tables the new project already has.
The restore is one transaction. It checks every table's row count against the manifest
written at backup time, and a mismatch rolls all of it back, so you never end up with a
half-loaded project. With a customer-managed key, set SAFEGRD_PRIVATE_KEY
to its contents first. A SafeGrd-managed key is released to your enrolled host, so the
restore needs nothing extra there.
We ran this on 11 October 2026 from a backup of one hosted project into a second, empty one: 42
tables and 25,915 rows, 50 users among them, in 57 seconds. The tables Supabase's own
services own (auth.schema_migrations, storage.migrations and
two more) cannot be written by postgres. The restore leaves them out and
names each with its row count. The new project already has its own copy of each.
Without SafeGrd, the same restore with pg_restore and psql is on
the Supabase backup page, under “Into a project,
after an incident”.
4. Restore the files in Storage
The database restore brought back the buckets and the record of every file, but not the files. Until they are uploaded, each one lists in Storage and answers 404. In the new project, create an S3 access key (Storage settings, S3 connection), then restore each bucket you back up:
Here SNAPSHOT_ID is the bucket's snapshot, not the database's. Each file goes
back with its content type, and its hash is checked against the backup's manifest as it
uploads. Storage updates the file record the database restore put back, so restore the
database first and the files second.
5. Put back what a dump does not carry
A database dump holds your data. These live in the project's settings or in Supabase's own services, and you set them again by hand:
| What | What to do |
|---|---|
| API keys and the project URL | The new project has new ones. Put them in your app's environment (section 6). |
| Auth providers and redirect URLs | Enable each provider again, with its client ID and secret, and add the new project's callback URL in Google, GitHub or whichever provider you use. Users' passwords come back with auth.users, so email sign-in works as before. |
| Signed-in sessions | Access tokens signed by the old project do not verify on the new one. Expect your users to sign in again. |
| Edge Functions | Deploy them from your repository with supabase functions deploy, and set their secrets again. |
| Database webhooks, Realtime publications | These live outside public, so the restore above leaves them out. Create them again, from your migrations if they are there. |
pg_cron jobs | SafeGrd’s backup records them, but a --schema restore creates none, so it cannot rewrite a job the new project already has. A restore of the whole database into an empty one creates each job turned off. Otherwise create them again with cron.schedule, from your migrations if they are there (details). |
| Vault secrets | They are encrypted with a key the dump cannot read, and the new project has a different key. Store each secret again. |
| Passwords of roles you created | Set them again with ALTER ROLE. |
| Custom domain, SMTP, network restrictions | Set them again in the dashboard. |
Write each of these into a runbook today, while nothing is down.
6. Point your app at the new project
- Change
SUPABASE_URL, the anon key and the service-role key wherever your app reads them: your hosting provider's environment, mobile build config, CI secrets. - Redeploy. A mobile app needs a release, or a config value it fetches at start.
- Sign in as a test user, load a page that reads data, and open one file from Storage.
- Tell your users what happened, and when the data is from: the backup's time is the last write they will see.
7. When the old project comes back
Pick one project to keep writing to. If both take writes, you will have two diverging copies of your data and no clean way to merge them.
- Staying on the new project is simplest: it has taken every write since the cutover. Pause the old one once you have checked it holds nothing newer than your backup.
- Going back to the old one means copying what the new project took since the cutover into it. Back up the new project first, then restore only the tables that changed.
The old project may hold writes made between your last backup and the outage. Compare the newest rows in your busiest tables before you pause it.
Before the next outage
- Keep a backup outside the project. Supabase's own backups restore into the same project, so a project that cannot start cannot use them. A dump in your own bucket, or in SafeGrd's hosted storage, does not depend on the project.
- Back up Storage too. Supabase's database backups leave the files out.
- Rehearse the move. SafeGrd's Fire Drills restore every backup on a schedule and record how long it took, so you know the restore works and how long section 3 will take. Once a quarter, run sections 2 to 6 into a scratch project and time them.
- Keep the settings in git. Edge Functions, cron jobs and webhooks in migrations, and a runbook for the rest of section 5.
Back up Supabase with SafeGrd with no server of your own, or from your repository with GitHub Actions.