Overview
Database migrations live insupabase/migrations/ and are applied sequentially to evolve the PostgreSQL schema. Each migration is a SQL file with a timestamp prefix.
File Naming Convention
The timestamp prefix determines execution order. Always use the current UTC timestamp when creating a new migration to avoid ordering conflicts with other developers.
Creating Migrations
Generate via CLI
supabase/migrations/ with the correct timestamp. Edit the file to add your SQL.
Manual Creation
Create a file directly:Migration Template
Applying Migrations
Via Supabase CLI (Recommended for Dev)
Push all pending migrations to the linked Supabase project:supabase_migrations.schema_migrations table and applies any new files in order.
Via SQL Editor (Production Hotfixes)
For urgent production fixes, you can run SQL directly in the Supabase Dashboard SQL Editor. After applying:- Create a matching migration file locally
- Insert the migration record manually so
db pushdoes not re-apply it:
Migration History Mismatch
Ifsupabase db push fails with a migration history mismatch:
Symptom
Fix
Key Migrations
Notable migrations in the history:| Migration | Description |
|---|---|
billing_infrastructure | Stripe billing tables, webhook event log, subscription management |
sync_control_maturity | Trigger that recalculates control maturity when evidence is validated |
integration_sync_cron | pg_cron jobs for nightly integration syncs and risk recompute |
unified_controls_seed | Seeds the 270+ unified controls and framework mappings |
rls_policies_v2 | Updated RLS policies for partner-through-tenant access |
evidence_pipeline | Evidence tables, validation workflow, certificate generation |
Best Practices
One concern per migration
One concern per migration
Each migration should address a single change. Do not combine unrelated schema changes. This makes rollbacks and debugging easier.
Always include DOWN logic in comments
Always include DOWN logic in comments
While Supabase does not have automatic rollback, document the undo SQL in comments for manual rollback if needed:
Test locally before pushing
Test locally before pushing
Use
supabase start to run migrations against a local database before applying to staging or production.Regenerate types after migration
Regenerate types after migration
After applying a migration, regenerate TypeScript types:
Handle RLS in the same migration
Handle RLS in the same migration
If you add a new table, include RLS policies in the same migration. A table without RLS is accessible to any authenticated user.