# How to Restore a Supabase Backup

- Tool: Supabase
- Difficulty: Intermediate
- Time required: 15-25 min
- Compatibility: Supabase Pro+ (point-in-time recovery), Free plan (manual pg_dump restore), PostgreSQL 15+
- Last updated: March 2026

## TL;DR

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.

## Before you start

- 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

### 1. 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.

### 2. 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.

```
# If you need to create a manual backup first:
pg_dump "postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres" \
  --clean \
  --if-exists \
  -F c \
  -f backup_20260327.dump
```

**Expected result:** A backup dump file is saved locally or downloaded from the Dashboard.

### 3. 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.

```
# Restore a plain SQL backup
psql "postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres" < backup.sql

# Or restore to a local Supabase instance for testing
supabase start
psql "postgresql://postgres:postgres@localhost:54322/postgres" < backup.sql
```

**Expected result:** The database schema and data are restored from the SQL backup file.

### 4. 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.

```
# Restore entire database from custom-format dump
pg_restore \
  --clean \
  --if-exists \
  -d "postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres" \
  backup_20260327.dump

# Restore only a specific table
pg_restore \
  -t products \
  --data-only \
  -d "postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres" \
  backup_20260327.dump

# List contents of a dump file (inspect before restoring)
pg_restore --list backup_20260327.dump
```

**Expected result:** The database or specific tables are restored from the custom-format dump file.

### 5. 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.

```
-- Check row counts for critical tables
SELECT 'users' AS table_name, count(*) FROM auth.users
UNION ALL
SELECT 'profiles', count(*) FROM public.profiles
UNION ALL
SELECT 'orders', count(*) FROM public.orders;

-- Verify RLS is enabled
SELECT tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public';

-- Check that RLS policies exist
SELECT tablename, policyname
FROM pg_policies
WHERE schemaname = 'public';
```

**Expected result:** Row counts match expected values, RLS is enabled on all tables, and policies are in place.

## Complete code example

File: `restore-supabase-backup.sh`

```bash
#!/bin/bash
# Supabase Database Restore Script
# Usage: ./restore-supabase-backup.sh <backup-file> <connection-string>

set -e

BACKUP_FILE=$1
CONNECTION_STRING=$2

if [ -z "$BACKUP_FILE" ] || [ -z "$CONNECTION_STRING" ]; then
  echo "Usage: ./restore-supabase-backup.sh <backup-file> <connection-string>"
  echo "Example: ./restore-supabase-backup.sh backup.dump 'postgresql://postgres.[ref]:[pass]@host:5432/postgres'"
  exit 1
fi

if [ ! -f "$BACKUP_FILE" ]; then
  echo "Error: Backup file '$BACKUP_FILE' not found"
  exit 1
fi

echo "=== Supabase Backup Restore ==="
echo "Backup file: $BACKUP_FILE"
echo ""

# Detect file format
FILE_TYPE=$(file "$BACKUP_FILE")

if echo "$FILE_TYPE" | grep -q "PostgreSQL"; then
  echo "Detected custom-format dump. Using pg_restore..."
  echo "Listing dump contents..."
  pg_restore --list "$BACKUP_FILE" | head -20
  echo "..."
  echo ""
  echo "Restoring database..."
  pg_restore \
    --clean \
    --if-exists \
    --no-owner \
    --no-privileges \
    -d "$CONNECTION_STRING" \
    "$BACKUP_FILE" 2>&1 || true
else
  echo "Detected SQL format dump. Using psql..."
  psql "$CONNECTION_STRING" < "$BACKUP_FILE"
fi

echo ""
echo "=== Verifying restore ==="
psql "$CONNECTION_STRING" -c "
SELECT schemaname, tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY tablename;"

echo ""
echo "Restore complete. Verify data in Supabase Dashboard."
```

## Common mistakes

- **Using the pooled connection string (port 6543) for pg_restore instead of the direct connection (port 5432)** — undefined Fix: Always use the direct connection string from Dashboard > Settings > Database for pg_dump and pg_restore operations.
- **Restoring a backup without first backing up the current state of the database** — undefined Fix: 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.
- **Restoring a full database dump when only a single table needs recovery, overwriting good data** — undefined Fix: 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

## 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.

---

Source: https://www.rapidevelopers.com/supabase-tutorial/how-to-restore-supabase-backup
© RapidDev — https://www.rapidevelopers.com/supabase-tutorial/how-to-restore-supabase-backup
