Guides / Supabase project down

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 seeWhy 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_UPThe new project waits on the same infrastructure team. One sat 11 hours with an empty cluster.
A paused Free project that will not resumeFree 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 problemYou 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

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:

safegrd list
export RESTORE_URL="postgres://postgres:PASSWORD@db.NEWPROJECT.supabase.co:5432/postgres"
safegrd restore --snapshot SNAPSHOT_ID --target env:RESTORE_URL \
  --schema public --data-only-schema auth --data-only-schema storage

--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:

safegrd restore --snapshot SNAPSHOT_ID --target s3://avatars \
  --source-endpoint https://NEWPROJECT.storage.supabase.co/storage/v1/s3 --source-region REGION \
  --source-access-key env:SUPABASE_S3_KEY --source-secret-key env:SUPABASE_S3_SECRET

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:

WhatWhat to do
API keys and the project URLThe new project has new ones. Put them in your app's environment (section 6).
Auth providers and redirect URLsEnable 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 sessionsAccess tokens signed by the old project do not verify on the new one. Expect your users to sign in again.
Edge FunctionsDeploy them from your repository with supabase functions deploy, and set their secrets again.
Database webhooks, Realtime publicationsThese live outside public, so the restore above leaves them out. Create them again, from your migrations if they are there.
pg_cron jobsSafeGrd’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 secretsThey 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 createdSet them again with ALTER ROLE.
Custom domain, SMTP, network restrictionsSet 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

  1. 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.
  2. Redeploy. A mobile app needs a release, or a config value it fetches at start.
  3. Sign in as a test user, load a page that reads data, and open one file from Storage.
  4. 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.

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

Back up Supabase with SafeGrd with no server of your own, or from your repository with GitHub Actions.