Migrations
Generating, applying, and managing database migrations with Drizzle.
Quick reference
td db generate <name> # Generate migration from schema changes
td db migrate # Apply pending migrations locally
td migrations # Show applied vs pendingCreating a migration
After editing schema in shared/db/src/:
td db generate add-widget-tableThis diffs your schema against the last migration and creates a numbered SQL file in shared/db/migrations/. Review the generated SQL before committing — Drizzle is accurate but it's worth a sanity check, especially for destructive operations.
Applying migrations
td db migrate # Apply all pending locally
td migrations # Check status: applied vs pendingIn production (Railway), migrations run automatically as a preDeployCommand before the new container takes traffic. This means a failed migration will block the deploy rather than crash a live instance.
Migration rules
-
Never edit existing migration files — create a new migration instead. Editing a file that's already been applied to production will cause a checksum mismatch and break subsequent runs.
-
Make schema changes additive — add nullable columns first, backfill data, then add
NOT NULL. A migration adding aNOT NULLcolumn to a table with millions of rows will lock the table. -
One logical change per migration — keep them small and focused. A migration that adds a table, renames a column, and adds an index is three things and harder to reason about or roll back.
-
Test with real data — migrations that work on an empty local database may fail on a staging database with real data. Check row counts and data distributions before deploying.
Checking migration status
td migrations
# ✓ 0001_initial_schema applied 2024-01-10
# ✓ 0002_add_content_status applied 2024-01-15
# ✗ 0003_add_newsletters pendingtd migrations --pr current checks the status in the PR preview environment — useful for verifying your migration actually ran.
Rollback strategy
Drizzle doesn't have automatic rollbacks. For breaking changes:
- Write a compensating migration that undoes the change
- Test in a preview environment before touching production
- Have the compensating migration ready to apply if needed
For truly destructive changes (dropping a column with data), always take a database snapshot before deploying.