# Database Migration Strategy ## Drizzle ORM Migrations ### Development (Local / Test) Use `db:push` for rapid iteration: ```bash bun run db:push ``` This syncs schema directly — fast but destructive. Fine for dev/test. ### Production Use `db:migrate` with generated migration files: ```bash bun run db:generate # creates SQL migration file bun run db:migrate # applies migration ``` ### Workflow 1. Change schema in `src/db/schema.ts` 2. Run `bun run db:generate` — creates migration in `drizzle/` 3. Review the generated SQL 4. Write rollback SQL in `drizzle/rollback/` (same filename) 5. Test migration on staging 6. Apply to production ## Safe Migration Practices ### Adding columns - Always add as nullable or with a default value - Never add non-nullable columns without defaults to tables with existing data ### Removing columns - First deploy: stop reading/writing the column in code - Second deploy: remove the column from schema - Two-phase approach prevents errors during rolling deploys ### Renaming columns - Don't rename directly — add new column, migrate data, remove old column ### Adding indexes - Use `CREATE INDEX CONCURRENTLY` for large tables (avoids locks) - Drizzle may not generate concurrent indexes — check generated SQL ## Backup Before Migration Always backup before production migrations: ```bash pg_dump -Fc $DATABASE_URL > backup-$(date +%Y%m%d-%H%M%S).dump ```