50 lines
1.4 KiB
Markdown
50 lines
1.4 KiB
Markdown
# 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
|
|
```
|