To restore a Supabase backup, use the point-in-time recovery feature in the Dashboard for Pro plan projects, or restore a pg_dump file using psql or pg_restore on the command line. Point-in-time recovery lets you restore to any second within the retention window. For manual backups, download the dump file from the Dashboard and restore it to a new or existing project using the direct database connection string.
Restoring a Supabase Database Backup
Database disasters happen — accidental deletes, bad migrations, or corrupted data. Supabase provides two restoration paths: point-in-time recovery (PITR) for Pro and Enterprise plans, which lets you restore to any second within your retention window, and manual restoration from pg_dump files for all plans. This tutorial covers both methods, from clicking a button in the Dashboard to running pg_restore on the command line.
Prerequisites
- A Supabase project with an existing backup (PITR or pg_dump file)
- Supabase CLI installed for command-line restore
- Your database connection string from Dashboard > Settings > Database
- psql or pg_restore installed locally (included with PostgreSQL)
Step-by-step guide
Restore using point-in-time recovery in the Dashboard
Restore using point-in-time recovery in the Dashboard
For Supabase Pro and Enterprise plans, point-in-time recovery (PITR) lets you restore your database to any point within the retention period (7 days on Pro, 30 days on Enterprise). Go to the Supabase Dashboard > Settings > Database > Backups. Select the Point-in-Time tab. Choose the date and time you want to restore to, then click Restore. Supabase will create a new database state matching that exact point in time. This process can take several minutes depending on database size.
Expected result: Your database is restored to the selected point in time. All data changes after that point are removed.
Download a backup file from the Dashboard
Download a backup file from the Dashboard
Supabase creates daily automatic backups for Pro plans and above. Go to Dashboard > Settings > Database > Backups > Scheduled Backups tab. You will see a list of available backups with dates. Click Download on the backup you want to restore. For free plan projects, you need to create your own backups using pg_dump before you can restore. The downloaded file is a PostgreSQL dump that can be restored with psql.
1# If you need to create a manual backup first:2pg_dump "postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres" \3 --clean \4 --if-exists \5 -F c \6 -f backup_20260327.dumpExpected result: A backup dump file is saved locally or downloaded from the Dashboard.
Restore a SQL format backup with psql
Restore a SQL format backup with psql
If your backup is a plain SQL file (created with pg_dump without -F c), restore it using psql. Connect to your Supabase database using the direct connection string (port 5432, not the pooled port 6543) and pipe the SQL file into it. The --clean flag in the original dump means it will drop existing objects before recreating them. Make sure no other applications are actively writing to the database during the restore.
1# Restore a plain SQL backup2psql "postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres" < backup.sql34# Or restore to a local Supabase instance for testing5supabase start6psql "postgresql://postgres:postgres@localhost:54322/postgres" < backup.sqlExpected result: The database schema and data are restored from the SQL backup file.
Restore a custom-format backup with pg_restore
Restore a custom-format backup with pg_restore
Custom-format dumps (created with pg_dump -F c) offer more flexibility. Use pg_restore to restore the entire dump or selectively restore specific tables. The --clean flag drops existing objects before restoring, and --if-exists prevents errors if an object does not exist. Use the -t flag to restore a single table, which is useful when you only need to recover specific data.
1# Restore entire database from custom-format dump2pg_restore \3 --clean \4 --if-exists \5 -d "postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres" \6 backup_20260327.dump78# Restore only a specific table9pg_restore \10 -t products \11 --data-only \12 -d "postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres" \13 backup_20260327.dump1415# List contents of a dump file (inspect before restoring)16pg_restore --list backup_20260327.dumpExpected result: The database or specific tables are restored from the custom-format dump file.
Verify data integrity after the restore
Verify data integrity after the restore
After restoring, verify that the data is correct and complete. Check row counts for critical tables, verify that RLS policies are in place, and test that your application can connect and query data normally. Compare the restored state against known data points — for example, check whether a specific user record exists or whether the total order count matches expectations. Also verify that functions, triggers, and indexes were restored correctly.
1-- Check row counts for critical tables2SELECT 'users' AS table_name, count(*) FROM auth.users3UNION ALL4SELECT 'profiles', count(*) FROM public.profiles5UNION ALL6SELECT 'orders', count(*) FROM public.orders;78-- Verify RLS is enabled9SELECT tablename, rowsecurity10FROM pg_tables11WHERE schemaname = 'public';1213-- Check that RLS policies exist14SELECT tablename, policyname15FROM pg_policies16WHERE schemaname = 'public';Expected result: Row counts match expected values, RLS is enabled on all tables, and policies are in place.
Complete working example
1#!/bin/bash2# Supabase Database Restore Script3# Usage: ./restore-supabase-backup.sh <backup-file> <connection-string>45set -e67BACKUP_FILE=$18CONNECTION_STRING=$2910if [ -z "$BACKUP_FILE" ] || [ -z "$CONNECTION_STRING" ]; then11 echo "Usage: ./restore-supabase-backup.sh <backup-file> <connection-string>"12 echo "Example: ./restore-supabase-backup.sh backup.dump 'postgresql://postgres.[ref]:[pass]@host:5432/postgres'"13 exit 114fi1516if [ ! -f "$BACKUP_FILE" ]; then17 echo "Error: Backup file '$BACKUP_FILE' not found"18 exit 119fi2021echo "=== Supabase Backup Restore ==="22echo "Backup file: $BACKUP_FILE"23echo ""2425# Detect file format26FILE_TYPE=$(file "$BACKUP_FILE")2728if echo "$FILE_TYPE" | grep -q "PostgreSQL"; then29 echo "Detected custom-format dump. Using pg_restore..."30 echo "Listing dump contents..."31 pg_restore --list "$BACKUP_FILE" | head -2032 echo "..."33 echo ""34 echo "Restoring database..."35 pg_restore \36 --clean \37 --if-exists \38 --no-owner \39 --no-privileges \40 -d "$CONNECTION_STRING" \41 "$BACKUP_FILE" 2>&1 || true42else43 echo "Detected SQL format dump. Using psql..."44 psql "$CONNECTION_STRING" < "$BACKUP_FILE"45fi4647echo ""48echo "=== Verifying restore ==="49psql "$CONNECTION_STRING" -c "50SELECT schemaname, tablename, rowsecurity51FROM pg_tables52WHERE schemaname = 'public'53ORDER BY tablename;"5455echo ""56echo "Restore complete. Verify data in Supabase Dashboard."Common mistakes when restoring a Supabase Backup
Why it's a problem: Using the pooled connection string (port 6543) for pg_restore instead of the direct connection (port 5432)
How to avoid: Always use the direct connection string from Dashboard > Settings > Database for pg_dump and pg_restore operations.
Why it's a problem: Restoring a backup without first backing up the current state of the database
How to avoid: Always create a fresh pg_dump of the current database before restoring. This gives you a way to revert if the restored state is not what you expected.
Why it's a problem: Restoring a full database dump when only a single table needs recovery, overwriting good data
How to avoid: Use pg_restore with -t tablename --data-only to selectively restore just the table you need without affecting other tables.
Best practices
- Always back up the current database state before performing any restore operation
- Test restores on a local Supabase instance with supabase start before applying to production
- Use custom-format dumps (-F c) for backups because they support selective table restoration
- Verify RLS policies and row counts after every restore to ensure data integrity
- Use point-in-time recovery for recent data loss on Pro plans instead of manual restore
- Keep a restore verification checklist with critical data points to check after every restore
- Document the restore procedure for your team so anyone can perform it in an emergency
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I accidentally deleted important data from my Supabase database. Walk me through restoring from a pg_dump backup file using pg_restore, including how to selectively restore just one table without overwriting other data. Also explain how point-in-time recovery works on Supabase Pro plans.
Write a shell script that restores a Supabase database from a pg_dump file. The script should detect whether the file is SQL or custom format, restore accordingly, and then verify the restore by checking table counts and RLS policy status.
Frequently asked questions
Is point-in-time recovery available on the free plan?
No. Point-in-time recovery requires a Pro plan or higher. Free plan users must create manual backups with pg_dump and restore from those files.
How far back can I restore with point-in-time recovery?
Pro plans have a 7-day retention window. Enterprise plans have a 30-day retention window. You can restore to any second within that window.
Can I restore a backup to a different Supabase project?
Yes. Use pg_restore or psql with the connection string of the target project. This is useful for creating a staging environment from production data.
Will restoring a backup affect my RLS policies?
If you used pg_dump without --data-only, the dump includes RLS policies and they will be restored. If you used --data-only, only data is restored and existing policies remain unchanged.
How long does a restore take?
It depends on database size. Small databases (under 1 GB) typically restore in under 5 minutes. Larger databases can take 15-30 minutes or more. Point-in-time recovery may take longer depending on the amount of WAL data to replay.
Can I restore just one table from a backup?
Yes, but only from custom-format dumps (created with pg_dump -F c). Use pg_restore -t tablename --data-only to restore just the data for that table. Plain SQL dumps do not support selective restore.
Can RapidDev help with database recovery and restore procedures?
Yes. RapidDev can set up automated backup schedules, write restore scripts, test recovery procedures, and help recover from data loss incidents. They can also configure point-in-time recovery and verify data integrity after restores.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation