Most founders assume their database is backed up because it's hosted. Sometimes it is. Sometimes the backup exists but can't be restored the way they expect. And sometimes there is no backup at all, because the project is on a plan that doesn't include one.
This guide covers what Supabase backups give you in general terms, what they leave out, and how to prove you can actually get your data back. Plans and retention periods change, so confirm the current details in the Supabase docs and your project's Database settings before relying on them.
What you get depends on your plan
- Free projects: don't count on managed backups you can restore. If a free project holds anything you care about, take your own backups.
- Paid plans: daily backups are included and kept for a number of days that grows with the plan tier. You can restore from them in the dashboard.
- Point-in-time recovery (PITR): an add-on for paid projects that lets you restore to a specific moment, not just to last night.
To see what your project has right now, open the dashboard and go to Database, then Backups. If the page shows no restorable backups, that's your answer, and it's better to find out today than during an incident.
Daily backups versus point-in-time recovery
A daily backup is a snapshot. If something goes wrong at 4pm, restoring the overnight backup loses everything written since then: sign-ups, orders, messages.
Point-in-time recovery continuously archives the database's write-ahead log, so you can roll back to just before the bad moment. That's the difference between losing a few seconds and losing most of a day.
PITR is worth considering when:
- Users create data all day, like orders, bookings or content they'd be upset to lose.
- You or an AI agent run migrations or bulk updates against production.
- Losing a day of data would mean refunds, apologies or legal exposure.
It costs extra and has compute requirements, so check the current pricing page. For an early project with little live data, solid daily backups plus your own exports may be enough.
What Supabase backups don't cover
Database backups cover your Postgres database. Several things people assume are included often aren't:
- Files in Supabase Storage. The database holds metadata about your files, but the files themselves need their own backup plan.
- Edge Function code and secrets. Keep function code in Git and store secrets somewhere you can recreate them from.
- Project settings, like auth providers, redirect URLs, SMTP settings and API configuration. Write these down or manage them as config.
- Anything in third-party services, like Stripe, your email provider or analytics.
Also know how a dashboard restore behaves. Restoring a project's backup typically replaces the current database and involves downtime. Read the restore options in the dashboard before an emergency, and check whether restoring to a separate project is available to you.
Take your own backups too
Even on a paid plan, an independent copy you control is cheap insurance. The Supabase CLI can dump a project's roles, schema and data into SQL files. Use your database connection string from the dashboard's Connect panel.
supabase db dump --db-url "$DB_URL" -f roles.sql --role-only
supabase db dump --db-url "$DB_URL" -f schema.sql
supabase db dump --db-url "$DB_URL" -f data.sql --use-copy --data-onlyRun this on a schedule, for example from a GitHub Actions workflow, and store the files somewhere private and encrypted, with access limited to people who need it. These dumps contain all your users' data, so treat them like production.
How to test a restore
A backup you've never restored is a hope, not a plan. Test it on a fresh project, never on production.
- Create a new, empty Supabase project to act as the restore target.
- Restore your dump into it with psql, loading roles first, then schema, then data.
- Count rows in your most important tables and compare them to production.
- Point a local copy of your app at the restored project and sign in as a test user.
- Check that RLS policies, functions, triggers and extensions came across.
- Write down how long it took and every step that surprised you.
- Delete the test project when you're done, since it holds real user data.
psql --single-transaction --variable ON_ERROR_STOP=1 \
--file roles.sql --file schema.sql \
--command 'SET session_replication_role = replica' \
--file data.sql \
--dbname "$RESTORE_DB_URL"Setting session_replication_role to replica while loading data stops triggers from firing during the import, so rows load without side effects. Expect a few errors the first time, often around extensions or objects Supabase manages itself. Fixing them now is the whole point of the test.
A simple backup routine
- Confirm in the dashboard which backups your plan actually provides.
- Decide whether a day of lost data is acceptable. If not, look at PITR.
- Schedule your own CLI dumps and store them privately.
- Back up Storage files and keep function code and settings in Git.
- Test a full restore at least once, and again after big schema changes.
Deeraf checks backups and restore readiness as part of every Supabase audit, alongside RLS and keys. On Call can include a restore test on a regular schedule, so it's never a first attempt during an outage.