prisma-expand-contract
Prisma Expand-and-Contract Migrations
Safe, zero-downtime database schema changes with Prisma ORM.
When to Use
- Renaming columns or tables in production
- Changing column types (e.g.,
StringtoEnum) - Adding non-nullable columns to tables with existing data
- Splitting or merging tables
- Any schema change that could break running instances during deployment
The Pattern
Split destructive changes into three phases across multiple deployments:
EXPAND MIGRATE CONTRACT
Add new structure → Copy data, → Remove old structure
update code
Deploy 1 Deploy 2 Deploy 3
Why: During deployment, old and new application versions run simultaneously. Direct renames or type changes break old instances immediately.
Core Principles
- Never remove in the same deploy as you add - Old code must continue working
- Make changes additive first - Add new columns/tables before removing old
- Code handles both states - During transition, read from new, write to both
- Data migration between deploys - Not during schema migration
- Cleanup is separate - Remove old structures only after all code uses new
Prisma Tools for Renames
@map (Column-Level)
Maps Prisma field to different database column:
model User {
displayName String @map("user_name") // Prisma: displayName, DB: user_name
}
@@map (Table-Level)
Maps Prisma model to different database table:
model Account {
id String @id
@@map("users") // Prisma: Account, DB: users
}
Note: @map/@@map only work for code-level renames. For actual data migration, use full expand-and-contract.
@default (Safe Non-Nullable Addition)
For new columns where a default makes sense:
model User {
createdAt DateTime @default(now()) // Safe to add directly
isActive Boolean @default(true) // Safe to add directly
}
Common Scenarios
| Scenario | Approach |
|---|---|
| Rename column | Add new → backfill → make required → remove old |
| Change type (String→Enum) | Add enum column → backfill mapping → switch reads → remove string |
| Add non-nullable column | Add nullable → backfill → make required |
| Rename table | Create new table → copy data → migrate code → drop old |
| Split table | Add related table → copy data → update code → remove old fields |
For detailed step-by-step implementations, see SCENARIOS.md.
Anti-Patterns
Direct Column Rename
// DON'T: Breaks running instances immediately
model User {
displayName String // Was: userName
}
Remove and Add in Same Migration
// DON'T: Old code fails during deployment
model User {
// Removed: userName
displayName String // Added
}
migrate dev in Production
# DON'T: Can cause data loss
npx prisma migrate dev
# DO: Use migrate deploy
npx prisma migrate deploy
Non-Nullable Without Backfill
// DON'T: Migration fails if nulls exist
model User {
email String // Changed from String?
}
Quick Reference
npx prisma migrate dev --name name # Development: create + apply
npx prisma migrate deploy # Production: apply pending
npx prisma migrate status # View migration status
For deployment checklists and rollback strategies, see CHECKLISTS.md.
Additional Resources
More from kbravh/skills
svg-logo-creator
Create professional SVG logos from concept briefs or descriptions. Use when generating SVG logo files, creating logo variations (horizontal, vertical, icon-only), or implementing logo designs. Triggers on "create SVG logo," "generate logo," "make a logo," "logo SVG," "design a logo," or when given a logo concept brief from logo-ideation.
69logo-ideation
Brand discovery and logo concept development. Use when brainstorming logo ideas, exploring visual directions, analyzing competitor logos, or developing logo concepts before creation. Triggers on "logo ideas," "logo concept," "brand identity," "logo brainstorm," "competitor logos," "visual identity exploration," or any pre-design logo planning.
23tanstack-query
TanStack Query (React Query) v5 best practices for data fetching, caching, and mutations. Use when fetching server data with useQuery, setting up mutations with useMutation, configuring caching strategies, managing query keys, handling optimistic updates, invalidating queries, or integrating TanStack Query into a React/TypeScript project. Triggers on "React Query", "TanStack Query", "useQuery", "useMutation", "query keys", "stale time", "cache invalidation", "optimistic update", "prefetch", "infinite query".
5