This guide explains how to migrate data (not just schema) from one Supabase database to another.
COMPLETE_SCHEMA_ADDITIONS.sql= Creates/updates database structure (tables, columns, indexes)DATA_MIGRATION_SCRIPT.sql= Copies actual data from one database to another
Best for: < 10,000 records per table
-
Export from Source Database:
- Go to Supabase Dashboard → SQL Editor
- Run:
SELECT * FROM table_name; - Export results as CSV
-
Import to Target Database:
- Go to Supabase Dashboard → Table Editor
- Select your table
- Click "Import" → Upload CSV
- Map columns correctly
Best for: > 10,000 records or full database migration
# Step 1: Export from source database
pg_dump -h source-db-host.supabase.co \
-U postgres \
-d postgres \
-t public.clients \
-t public.locations \
-t public.reviews \
--data-only \
--column-inserts \
> migration_data.sql
# Step 2: Import to target database
psql -h target-db-host.supabase.co \
-U postgres \
-d postgres \
-f migration_data.sqlBest for: Complex migrations, data transformation, validation
Create a Node.js script:
// migrate-data.ts
import { createClient } from '@supabase/supabase-js';
const sourceSupabase = createClient(
'https://source-project.supabase.co',
'source-service-key'
);
const targetSupabase = createClient(
'https://target-project.supabase.co',
'target-service-key'
);
async function migrateTable(tableName: string) {
console.log(`Migrating ${tableName}...`);
// Fetch from source
const { data, error } = await sourceSupabase
.from(tableName)
.select('*');
if (error) throw error;
// Insert into target (in batches)
const batchSize = 100;
for (let i = 0; i < data.length; i += batchSize) {
const batch = data.slice(i, i + batchSize);
const { error: insertError } = await targetSupabase
.from(tableName)
.insert(batch);
if (insertError) {
console.error(`Error inserting batch ${i}:`, insertError);
}
}
console.log(`✅ Migrated ${data.length} records from ${tableName}`);
}
// Run migration
async function main() {
const tables = [
'clients',
'locations',
'reviews',
'metrics_impressions',
'metrics_snapshot',
'keyword_scans',
'citations',
'websites',
// ... other tables
];
for (const table of tables) {
await migrateTable(table);
}
}
main();# Install Supabase CLI
npm install -g supabase
# Link to source project
supabase link --project-ref source-project-ref
# Export data
supabase db dump --data-only -f migration.sql
# Link to target project
supabase link --project-ref target-project-ref
# Import data
supabase db reset
psql -f migration.sqlMigrate tables in this order to respect foreign key dependencies:
- ✅ clients (no dependencies)
- ✅ memberships (depends on clients)
- ✅ locations (depends on clients)
- ✅ websites (depends on clients)
- ✅ reviews (depends on locations)
- ✅ metrics_impressions (depends on locations)
- ✅ metrics_snapshot (depends on locations)
- ✅ keyword_scans (depends on locations)
- ✅ citations (depends on locations)
- ✅ web_keywords (depends on websites)
- ✅ web_pages (depends on websites)
- ✅ web_keyword_ranks (depends on web_keywords)
- ✅ web_page_metrics (depends on web_pages)
- ✅ web_competitors (depends on websites)
- ✅ web_competitor_metrics (depends on web_competitors)
- ✅ web_audit_summary (depends on websites)
- ✅ web_audit_issues (depends on websites)
- ✅ web_backlink_summary (depends on websites)
-- Run schema additions first
-- Execute: COMPLETE_SCHEMA_ADDITIONS.sqlChoose your method:
- Small data: Use Supabase Dashboard export
- Large data: Use pg_dump
- Complex: Use application script
Common transformations:
- UUID mapping (if IDs need to change)
- User ID mapping (if auth.users differ)
- Date format conversion
- Null value handling
Import in the correct order (see Migration Order above).
-- Check record counts
SELECT
'clients' as table_name, COUNT(*) as count FROM public.clients
UNION ALL
SELECT 'locations', COUNT(*) FROM public.locations
UNION ALL
SELECT 'reviews', COUNT(*) FROM public.reviews;
-- Check sample data
SELECT * FROM public.clients LIMIT 5;
SELECT * FROM public.reviews LIMIT 5;- ✅ Test login
- ✅ Test dashboard loading
- ✅ Test data queries
- ✅ Verify relationships work
Users are NOT automatically migrated!
Supabase users are in auth.users which requires special handling:
-- Option 1: Manual user creation in target
-- Users must sign up again or be imported via Supabase Auth API
-- Option 2: Export/import auth.users (requires admin access)
-- This is complex and may require Supabase support- Disable foreign key checks during migration if needed:
SET session_replication_role = 'replica';
-- ... run inserts ...
SET session_replication_role = 'origin';If source and target have overlapping UUIDs:
- Option 1: Generate new UUIDs (breaks relationships)
- Option 2: Use same UUIDs (recommended)
- Option 3: Create mapping table
After migration, verify RLS policies:
-- Check if RLS is enabled
SELECT tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public';
-- Re-enable if needed
ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;- Solution: Migrate tables in correct order (see Migration Order)
- Solution: Use
ON CONFLICT DO NOTHINGorON CONFLICT DO UPDATE
- Solution: Use service role key, not anon key
- Solution: Run
COMPLETE_SCHEMA_ADDITIONS.sqlfirst
- Solution:
- Use batch inserts (100-1000 records at a time)
- Disable indexes temporarily
- Use
COPYinstead ofINSERTfor large datasets
# Export single table
pg_dump -h source.supabase.co -U postgres -d postgres \
-t public.clients --data-only > clients.sql
# Import single table
psql -h target.supabase.co -U postgres -d postgres -f clients.sql
# Export all tables
pg_dump -h source.supabase.co -U postgres -d postgres \
--data-only --schema=public > all_data.sql
# Import all tables
psql -h target.supabase.co -U postgres -d postgres -f all_data.sql- ✅ Run
COMPLETE_SCHEMA_ADDITIONS.sqlon target database - ✅ Choose migration method based on data size
- ✅ Export data from source database
- ✅ Import data to target database (in correct order)
- ✅ Verify migration success
- ✅ Test application functionality
Need Help?
- Check Supabase documentation for pg_dump/pg_restore
- Use Supabase Dashboard for small datasets
- Create application script for complex migrations