Skip to content

Backups

How to restore a Supabase backup, and what breaks after

How to restore a Supabase backup from the dashboard or from a dump file, what the restore replaces, and why your app can still be broken when it finishes.

Vlad Tkachenko11 min read
A saved copy opening into a database, its rows arriving one after another and filling the empty space below them.

In short

  • To restore a Supabase backup you either roll the project back from the dashboard, or replay a dump file into a project with psql. Which one is open to you was decided before today.
  • Copy the database as it is now before you restore anything. A restore replaces the tables in the copy, so every row written since goes with them.
  • The common outcome is a restore that succeeds and an app that is still broken, because your uploaded files and your login accounts were never in the database copy.

Something in your database is wrong, and for once you have a copy of it. Now you are looking at a button you have never pressed, on a project with real users in it, working out what it is about to do to them.

Here is the part that guide after guide leaves out. Almost every article on how to restore a Supabase backup stops at the moment the restore finishes, and that is where most of the trouble starts. The common outcome is not a restore that fails. It is one that succeeds and leaves the app broken anyway, because a database backup only ever held the database.

It helps to stop picturing this as putting your data back. A restore swaps your database for an older one, closer to exchanging a whole filing cabinet than to refiling one folder. Everything below follows from that.

How do I restore a Supabase backup?

Three routes, and which of them is open to you today was decided before today.

RouteWhat it doesWhat it needs
The Supabase dashboardReplaces the database in that project with a dated nightly copy you pickA paid plan, and the copy still sitting inside your window
Point-in-time recoveryRewinds the whole project to a minute you nameThe PITR add-on, bought before the thing you are recovering from
A dump file, replayed with psqlLoads the file into whichever project you point it at, new ones includedThe file, and the database password for the target project

The first two put your data back where it already was. The third is the only one that can put it somewhere else, which is what you need on the day the problem is your account rather than your data.

If you are not sure which of these you have, which Supabase plan you are on settles the first two and takes about two minutes to check.

Copy what you have now, before you restore anything

Take a copy of the database in its current broken state first. It is one command, and it is what makes every decision after it reversible.

pg_dump "postgresql://…your connection string…" \
  --clean --if-exists --no-owner \
  --file before-restore-2026-08-24.sql

There are two reasons, and people usually learn the second one afterwards.

The first is that a restore is a replacement. The tables in the copy come back exactly as they were, so every row written to them since goes too. A customer who signed up this morning is a row you are about to delete on purpose.

The second is that your broken database is still the only place some of your data exists. If the copy is from Tuesday and the damage happened on Thursday, everything created on Wednesday is sitting in front of you right now and nowhere else. Restore over it and it goes a second time, by your hand rather than by the accident.

While you work, turn off anything that writes new rows. The reasoning is the same as after any bad delete: the gap between the copy and now gets more expensive the longer the app keeps filling it.

Restoring from the Supabase dashboard

This replaces the database in your project with the copy you choose, and the project is unavailable while it runs.

Open the project your app talks to, find Database and then Backups, and pick the dated copy you want. Read the exact steps in Supabase's own backup documentation, because the dashboard gets rearranged and this page will not notice when it does.

How long it takes depends on the size of your database, which is Supabase's own answer. Put up a maintenance notice before you begin.

Point-in-time recovery is the same operation with a finer dial. Instead of picking last night you name a minute, and the project rewinds to it. Supabase describes it as destructive, which is the right word for it. Their troubleshooting notes also say a point-in-time restore cannot start until existing replication slots and subscriptions are removed, so if anything in your app streams database changes as they happen, that is a step to take first rather than an error to hit halfway through.

Neither route can put your data into a different project. Both act on the project you are standing in, which means both are unavailable on the day the thing that went wrong is your access to the account.

Restoring a dump file with psql

You point psql at a project and replay the file into it. That project can be the one you had, or a brand new one on an account you opened this morning.

psql -d "postgresql://…the target project's connection string…" \
  --variable ON_ERROR_STOP=1 \
  --single-transaction \
  --file backup-2026-08-09.sql

Two of those flags are worth understanding, because psql's default behaviour is the surprising one.

ON_ERROR_STOP=1 stops at the first error. Leave it out and psql reads the error, prints it, and carries on to the next line, so a file that failed on line 400 of 30,000 still ends at a prompt that looks like success, over a database missing everything after that line. --single-transaction wraps the whole file in one operation, so a failure leaves the database as it was instead of half changed.

Then the credential, which is where people get stuck. Replaying a backup means writing, so it needs something that can write. An anon key will not do it and neither will a read-only one. What psql wants is the database password for the target project, which lives in your Supabase project settings under Database.

What comes back depends on what is in the file, and that was settled when the dump was taken. Your login accounts are the part to check before you rely on it. They live in a schema called auth alongside the hashed passwords, and Supabase documents moving them between projects as a job with its own steps. If you are restoring into a new project and you want people to sign in with the password they already have, read that page before you start.

And a new project has a new URL and new keys. Your app is still pointed at the old one until you change it, which is the first line of the next section.

It restored, and the app is still broken

This is the ordinary outcome. It is almost always one of five things, and the first one takes a minute.

A restore lands on the schema your tables live in. Your uploaded files sit outside it and were never in the copy, and whether your login accounts come back depends on how that copy was taken.
What you seeWhat actually happenedWhat to do
The app loads and every list is emptyIt is still talking to the old projectPut the new project's URL and publishable key into your app's settings, then redeploy
Images, avatars and uploads are goneFiles live in Storage, outside the database. The rows you restored hold only the path to each fileRestore your files from their own copy. No database backup on any route contains them
Nobody can sign inLogin accounts live in the auth schema, and whether they were in the file depends on how the dump was takenFollow Supabase's auth migration guide, or restore again from a copy that includes that schema
Pages read fine and saving anything failsThe database came back readable and not writableCreate a row through the app before you call it done. The paragraph below has the detail
One feature is broken, its table is fineEdge functions live in your repository, outside the databaseRedeploy them from your builder or your repo

The fourth one deserves the attention. Permission to read and permission to write are granted separately, and a restore can land one and miss the other. So the pages fill with your data, everything looks recovered, and then the first person to submit a form gets an error. Looking at the app will never show you this, because looking is reading.

How to tell whether the restore actually worked

Sign in, find a row you can name, and then write one. In that order, and the last one is the check that counts.

Both go to the same restored database, and the rows are visibly there in both. Only the second one finds out whether the restore finished.
  • Sign in through the app the way a user would, rather than opening the Supabase table editor. That tests the app, the connection and the login accounts in one go.
  • Find a row you remember. A specific order, a named customer, the last thing you added before it broke. "The data looks like it is there" is a feeling; a row you can name is a check.
  • Compare a count against what you expected. Open your biggest table in the Supabase editor and read the number of rows. A restore that stopped partway usually shows up here as a number that is too small.
  • Then write something. Create a row the way a user does: place a test order, save a profile, post a comment. This is the check that fails when the other three pass, and it is the only thing that proves the restore finished.
  • Open something a user uploaded. If your app has images or attachments, click one. Whether your files came back is a separate question from whether your rows did.

What to do right now

What to do

  • Copy the database as it is now, before you restore anything. It is one pg_dump, and it is what makes the next decision reversible.
  • Turn off anything that writes new rows while you work, because a restore deletes whatever arrived after the copy was taken.
  • Match the route to the problem. A dashboard restore fixes your data; only a dump file replayed with psql can move your data to a new project.
  • If you are using psql, set ON_ERROR_STOP=1. A restore that quietly gave up partway looks exactly like one that worked.
  • Check the restore by writing, not by reading. Sign in, find a row you can name, then create one through the app.
  • Treat your uploaded files and your login accounts as separate jobs. Neither is finished when the database restore is.

Before you close this tab, find out whether you have anything to restore from at all, and where it is. That one answer decides which half of this article you will ever need. The 10-minute security checklist covers it alongside the other things worth confirming on a newly launched app, and the Supabase safety guide goes through what tends to be left open.

What Reeve Care does on the day you restore

The copy already exists, it has already been read back and checked, and it sits outside your Supabase account. That turns the hour above into a choice of which copy, and a button.

Four things it changes about this article specifically.

The copy has been verified before you need it. Every backup is read back and counted against what went in, and the date shown in your dashboard is the last copy that passed rather than the last one attempted. The half-finished restore this article warns about is a problem we find on an ordinary afternoon, before it is yours.

The safety copy is not a step you have to remember. Pressing restore takes a fresh copy of the current state first, so the restore itself can be undone.

Your uploaded files come back too, once you connect your Storage buckets. That is the row in the table above with no good answer otherwise.

The database key we hold can only read. A restore has to write, so it asks for your database password each time and keeps none of it. The optional key for your files can write, because Supabase issues no read-only key for Storage, and the page where you hand it over says so before you do.

The limits belong in the same breath, because you should know them before you pay rather than during an outage:

  • It works with Supabase and nothing else today.
  • You restore to a copy that exists, not to any minute you name. Worst case you lose one interval, which is up to a night on the entry plan and shorter on the two above it.
  • Login accounts are never touched. Nobody is signed out, deleted, or brought back.

Keep your Supabase backups switched on either way. Two copies in two places is the whole idea, and the cheaper of the two is already in your plan. What each Care plan covers is on the homepage.

If you would rather not pay for any of it, everything in this article still works. A pg_dump on a schedule you genuinely keep, held somewhere that losing your Supabase account would not also take, plus one practice restore a quarter, gets you most of the way there. The three routes and what each one misses covers that without a sales pitch.

The whole cycle is drawn out step by step on the Supabase backups page: the copy leaving Supabase, the check that follows it, and the button that puts it back.

FAQ

How do I restore a Supabase backup?

There are three routes. From the dashboard you pick a dated nightly copy and Supabase replaces that project database with it, which needs a paid plan. Point-in-time recovery rewinds the whole project to a minute you name, which needs the PITR add-on bought in advance. Or you replay a dump file into a project yourself with psql, which is the only route that can put your data into a different project on a different account. Before any of them, take a copy of the database as it is now.

Does restoring a backup delete the data added since it was taken?

Yes. A restore is a replacement rather than a merge: the tables in the copy come back exactly as they were at that moment, and everything written to them afterwards goes. That includes rows that were perfectly fine. It is the reason to stop your app writing before you start, and the reason to keep a copy of the current state so you can put the good newer rows back on top afterwards if you decide you want them.

My restore finished but the images in my app are missing. Why?

Because your files were never in the backup. Supabase Storage sits outside your Postgres database, so a database backup holds the row that points at each file and none of the files themselves. Restoring gives you a table full of links to things that are no longer there, or that are in a project you are no longer using. Storage has to be copied and restored separately, whichever backup route you took.

Can I restore a Supabase backup into a different project?

Only with a dump file you hold. The dashboard restore and point-in-time recovery both act on the project you are standing in, so neither helps on the day the problem is that you cannot get into the account at all. A pg_dump file replayed with psql goes into whichever project you point it at, including a brand new one on a new account. That is the difference the day it matters.

Will my users have to sign up again after a restore?

That depends on whether your login accounts were in the copy. They live in a database schema called auth, along with the hashed passwords, and Supabase documents moving them between projects as a job with its own steps rather than as something that rides along with your tables. If you are restoring into a new project, read that guide before you start. A restore inside the same project usually leaves sign-in alone.

How long does a Supabase restore take?

Supabase says it depends on the size of your database and how much data has to be processed, which is the honest answer and not a helpful one when you are waiting. Assume the project is unavailable for the duration and put up a maintenance notice before you begin. Their troubleshooting notes also say a point-in-time restore cannot start until existing replication slots and subscriptions are removed, so check that first if anything in your app streams database changes.

Written by

Vlad Tkachenko

Founder, Reeve

I spend my time looking at apps built with Lovable, Bolt, v0, Cursor and Replit, and at the short list of mistakes that keep turning up in them.

More about the author

Read next

Not sure where your own app stands?

Run a free scan and get a plain-language grade from A to F in about 20 seconds. No account, no card.

Scan your app free

Automated external check, not a full audit. Absence of findings is not a guarantee of safety.