Migration Files
Migrations are stored in thedrizzle/ directory:
Development Workflow
Local Development (Fast Iteration)
For rapid development, usedb:push to sync schema directly:
1
Edit Schema
Modify
lib/db/schema.ts to add/change tables or columns2
Push Changes
3
Test Changes
db:push is perfect for local development but doesn’t create migration files. It directly syncs your schema to the database.Production Workflow (Safe Deployment)
For production, always generate migration files:1
Edit Schema
Make your changes to
lib/db/schema.ts2
Generate Migration
drizzle/XXXX_name.sql3
Review Generated SQL
4
Test Locally
Apply the migration to your local database:
5
Commit Changes
6
Deploy
Push to GitHub. Migrations run automatically on Vercel deployment.
Common Migration Examples
Adding a Column
Schema change:Adding a New Table
Schema change:Adding a Foreign Key
Schema change:Renaming a Column
Schema change:Dropping a Column
Schema change:Migration Commands
Handling Destructive Changes Safely
Approach 1: Multi-Step Migration
Instead of dropping a column directly, use a multi-step approach: Step 1: Make column nullableApproach 2: Feature Flags
Use feature flags to gradually roll out schema changes:- Add new column (deploy)
- Update app to use new column (behind flag)
- Enable flag and migrate data
- Remove old column (new deployment)
Migration Conflicts
Resolving Conflicts
If multiple developers create migrations simultaneously:1
Pull Latest Changes
2
Check for Conflicts
Look for conflicts in
drizzle/meta/_journal.json3
Resolve Journal Conflicts
The journal tracks all migrations. Manually merge the arrays:
4
Regenerate Your Migration
5
Test Locally
Apply both migrations locally to ensure they work together
Rolling Back Migrations
Drizzle doesn’t have built-in rollback. Options:Option 1: Create Reverse Migration
Manually write SQL to undo the change:Option 2: Restore from Backup
For critical failures, restore from Neon backup:- Go to Neon Console → Your Branch → Backups
- Select point-in-time before migration
- Restore to a new branch
- Test and switch production
Option 3: Fix Forward
Create a new migration that fixes the problem:Seeding Data
Use seed scripts for initial configuration data:Best Practices
One Logical Change Per Migration
One Logical Change Per Migration
Keep migrations focused and atomic:✅ Good:
0048_add_task_tags.sql- Adds tags table and task_tag junction
0048_massive_refactor.sql- Adds tags, renames 5 columns, drops 3 tables
Always Review Generated SQL
Always Review Generated SQL
Don’t blindly trust auto-generated migrations:
Test Migrations Locally First
Test Migrations Locally First
Always apply migrations to local dev database before deploying:
Never Edit Applied Migrations
Never Edit Applied Migrations
Once a migration is deployed to production:
- Never edit the SQL file
- Create a new migration to fix issues
- Editing applied migrations breaks migration history
Add Indexes for Foreign Keys
Add Indexes for Foreign Keys
Drizzle doesn’t auto-create indexes on foreign keys. Add manually:
Document Breaking Changes
Document Breaking Changes
In commit messages and PR descriptions:
Troubleshooting
Migration Failed to Apply
Error: “relation ‘task’ does not exist” Fix:- Check if you’re on the correct database branch
- Verify all previous migrations are applied
- Check
drizzle/meta/_journal.jsonfor missing entries
Schema Out of Sync
Error: “Schema drift detected” Fix:Duplicate Migration
Error: “Migration 0048 already exists” Fix:CI/CD Integration
Migrations run automatically on Vercel deployments viapostinstall script:
Related Documentation
Database Overview
Database architecture and tools
Schema
Complete schema reference
Drizzle ORM
Query builder syntax
Deployment
How migrations run in production