Toast
Contributor

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 pending

Creating a migration

After editing schema in shared/db/src/:

td db generate add-widget-table

This 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 pending

In 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

  1. 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.

  2. Make schema changes additive — add nullable columns first, backfill data, then add NOT NULL. A migration adding a NOT NULL column to a table with millions of rows will lock the table.

  3. 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.

  4. 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       pending

td 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:

  1. Write a compensating migration that undoes the change
  2. Test in a preview environment before touching production
  3. 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.

On this page