supabase-migration-deep-dive
A guide to managing database schema evolution, backfills, rollbacks, and type generation using the Supabase CLI.
Install
mkdir -p .claude/skills/supabase-migration-deep-dive && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/5494" && unzip -o skill.zip -d .claude/skills/supabase-migration-deep-dive && rm skill.zipInstalls to .claude/skills/supabase-migration-deep-dive
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Database migration patterns with the Supabase CLI: npx supabase migration new, zero-downtime migrations, data backfill strategies, schema versioning, rollback strategies, and TypeScript type generation. Use when creating database migrations, performing zero-downtime schema changes, backfilling data in production, managing schema versions, or planning rollback strategies. Trigger with "supabase migration", "supabase schema change", "supabase zero downtime", "supabase rollback", "supabase db push", "supabase migration new".Key capabilities
- →Create timestamped SQL migration files
- →Execute zero-downtime schema modifications
- →Perform batch data backfills with rate limiting
- →Implement rollback strategies for failed migrations
How it works
It manages schema evolution through timestamped SQL files and CLI commands that ensure consistent application of changes across development, staging, and production environments.
Inputs & outputs
When to use supabase-migration-deep-dive
- →Creating database migrations
- →Performing zero-downtime schema changes
- →Backfilling data in production
- →Rolling back failed migrations
About this skill
Supabase Migration Deep Dive
Overview
Supabase migrations are timestamped SQL files managed by the CLI that track schema changes across environments. This skill covers the full lifecycle — creating migrations, zero-downtime schema changes, batch backfills, versioning, rollback, and TypeScript type generation — using real CLI commands and createClient from @supabase/supabase-js.
When to use: Creating new database migrations, modifying production schemas without downtime, backfilling existing data after adding columns, managing migration history across dev/staging/production, rolling back failed migrations, or regenerating TypeScript types.
Prerequisites
- Supabase CLI installed:
npm install -g supabaseornpx supabase --version @supabase/supabase-jsv2+ installed in your project- Local Supabase running:
npx supabase start - Understanding of PostgreSQL DDL and transaction behavior
Instructions
Step 1: Create and Manage Migrations
Create each migration as a timestamped SQL file, write the DDL, test it against a local reset, then promote it through environments with db push:
npx supabase migration new add_profiles_table # create timestamped SQL file
npx supabase migration list # show applied/pending status
npx supabase db reset # apply + seed locally (destructive)
npx supabase gen types typescript --local > lib/database.types.ts
npx supabase link --project-ref "<ref>" && npx supabase db push # promote to remote
Write DDL that enables RLS, adds policies, indexes, and triggers in the same file so the schema is complete when applied. For the full worked migration (a profiles table with RLS policies, an email index, a signup trigger, and an updated_at trigger) plus the local-test and staging/production promotion commands, see creating migrations.
Step 2: Zero-Downtime Migration Patterns
Production schema changes must avoid locking tables. The core rules: adding a nullable column with a default is lock-free on Postgres 11+; build indexes with CREATE INDEX CONCURRENTLY in a -- supabase:disable-transaction migration; rename or retype a column in two phases (add new column, backfill, sync trigger, then drop the old one) rather than an in-place ALTER COLUMN. Example of the safe column-add:
-- Nullable column with a default does NOT lock the table in Postgres 11+
ALTER TABLE public.orders ADD COLUMN status text DEFAULT 'pending';
-- Then, in a separate -- supabase:disable-transaction migration:
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_orders_status ON public.orders(status);
For the complete set — two-phase column rename with a sync trigger, safe type change via add-backfill-swap, and an SDK health-check that samples query latency during the migration — see zero-downtime patterns.
Step 3: Data Backfill, Versioning, and Rollback
See data backfill, versioning, and rollback for batch backfill patterns with the SDK, schema versioning across environments, three rollback strategies (compensating migration, repair, feature flags), and type regeneration after migrations.
Output
This skill produces:
- Migration creation workflow —
npx supabase migration newwith descriptive SQL files and local testing - Zero-downtime patterns — safe column additions, two-phase renames, concurrent index creation
- Batch backfill — SDK-based row-by-row updates with progress logging and rate limiting
- Schema versioning —
supabase migration listanddb difffor comparing environments - Rollback strategies — compensating migrations,
migration repair, and feature-flagged schema changes - Type regeneration —
supabase gen types typescriptafter every schema change - Migration promotion —
db pushworkflow from local to staging to production
Error Handling
| Error | Cause | Solution |
|---|---|---|
migration has already been applied | Re-running existing migration | Use supabase migration list to check status; never modify applied migrations |
cannot run inside a transaction block | CREATE INDEX CONCURRENTLY in transaction | Add -- supabase:disable-transaction comment at top of migration file |
column does not exist after migration | Migration not applied or types stale | Run supabase db push then supabase gen types typescript |
deadlock detected during backfill | Concurrent updates on same rows | Reduce batch size; add retry logic with exponential backoff |
statement timeout on large table | Migration takes longer than timeout | Increase statement_timeout in migration: SET statement_timeout = '300s'; |
migration repair failed | Wrong version number | Use exact version from supabase migration list (the timestamp prefix) |
db diff shows unexpected changes | Schema drift from manual SQL Editor changes | Run supabase db pull to capture manual changes as a migration |
| Type mismatch after migration | Generated types don't match new schema | Delete database.types.ts and regenerate from --local or --linked |
Examples
The create-write-test-push workflow for a real column addition:
npx supabase migration new add_tags_to_projects
cat > supabase/migrations/20260322150000_add_tags_to_projects.sql << 'SQL'
ALTER TABLE public.projects ADD COLUMN tags text[] DEFAULT '{}';
CREATE INDEX idx_projects_tags ON public.projects USING GIN(tags);
SQL
npx supabase db reset
npx supabase gen types typescript --local > lib/database.types.ts
npx supabase link --project-ref <staging-ref> && npx supabase db push
See examples for three full worked examples: the complete local-to-production migration workflow, a batch backfill with progress tracking from the SDK, and a safe enum migration using a CHECK constraint instead of ALTER TYPE.
Resources
- Database Migrations — Supabase Docs
- Supabase CLI Migration Commands
- supabase db push — Supabase Docs
- supabase gen types — Supabase Docs
- Zero-Downtime PostgreSQL Migrations
- supabase db diff — Supabase Docs
Next Steps
- For advanced troubleshooting after migrations, see
supabase-advanced-troubleshooting - For multi-environment migration promotion, see
supabase-multi-env-setup - For performance tuning after schema changes, see
supabase-performance-tuning
When not to use it
- →When performing trivial schema changes on small, non-production tables
- →When database locks are acceptable for maintenance windows
Prerequisites
Limitations
- →Requires careful handling of transaction blocks for concurrent operations
- →Large table migrations may require statement timeout adjustments
How it compares
It enforces a structured, version-controlled migration lifecycle instead of manual SQL execution in the dashboard.
Compared to similar skills
supabase-migration-deep-dive side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| supabase-migration-deep-dive (this skill) | 1 | 26d | Review | Intermediate |
| drizzle-orm | 32 | 2mo | No flags | Intermediate |
| database-design | 6 | 6mo | Review | Intermediate |
| prisma-expert | 12 | 6mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jeremylongshore
View all by jeremylongshore →You might also like
drizzle-orm
EpicenterHQ
Drizzle ORM patterns for type branding and custom types. Use when working with Drizzle column definitions, branded types, or custom type conversions.
database-design
davila7
Database design principles and decision-making. Schema design, indexing strategy, ORM selection, serverless databases.
prisma-expert
davila7
Prisma ORM expert for schema design, migrations, query optimization, relations modeling, and database operations. Use PROACTIVELY for Prisma schema issues, migration problems, query performance, relation design, or database connection issues.
database-schema-designer
davila7
Design robust, scalable database schemas for SQL and NoSQL databases. Provides normalization guidelines, indexing strategies, migration patterns, constraint design, and performance optimization. Ensures data integrity, query performance, and maintainable data models.
database-migrations-sql-migrations
sickn33
SQL database migrations with zero-downtime strategies for PostgreSQL, MySQL, SQL Server
postgresql-syntax-reference
pgschema
Consult PostgreSQL's parser and grammar (gram.y) to understand SQL syntax, DDL statement structure, and parsing rules when implementing pgschema features