Files
open-claw-team/.openclaw/workspace/skills/database-migrations/SKILL.md
T

117 lines
3.1 KiB
Markdown

---
name: database-migrations
description: Database migration patterns for Prisma, Drizzle, Django, SQLAlchemy, Go migrations. Use when: schema changes, adding columns/tables/indexes, data migrations, rollback strategies.
---
# Database Migration Patterns
Based on ECC database-migrations skill.
## Universal Rules
1. **Every migration is reversible** — always write DOWN (rollback) migration
2. **Deploy in phases** when possible:
- Phase 1: Add new column/table (non-breaking)
- Phase 2: Backfill data / dual-write
- Phase 3: Switch reads to new schema
- Phase 4: Remove old column/table
3. **Never drop data in a migration** without explicit user confirmation
4. **Test migrations** against a copy of production data
5. **Index new columns** that will be queried frequently
6. **Add NOT NULL with DEFAULT** when adding columns to existing tables
## Migration Strategy by Framework
### Prisma (TypeScript)
```bash
npx prisma migrate dev --name add_user_role
```
- Edit schema.prisma → generate migration → review → apply
- Always check the generated SQL
### Drizzle (TypeScript)
```bash
npx drizzle-kit generate:pg --name add_user_role
```
- Migration files are TypeScript
- Easier to review and modify than raw SQL
### Django (Python)
```bash
python manage.py makemigrations
python manage.py migrate
python manage.py showmigrations
```
- Django auto-detects changes
- For data migrations: use RunPython
- For complex operations: use migrations.RunSQL
### SQLAlchemy (Python)
```bash
alembic revision --autogenerate -m "add_user_role"
alembic upgrade head
```
- Review auto-generated migrations carefully
- Add missing operations manually
### Go (goose, golang-migrate)
```bash
goose create add_user_role sql
# or
migrate create -ext sql -dir migrations -seq add_user_role
```
- SQL files: up and down
- Explicit and reviewable
## Data Migration Patterns
### Adding a NOT NULL column with default
```sql
-- Safe: existing rows get default value
ALTER TABLE users ADD COLUMN role VARCHAR(50) NOT NULL DEFAULT 'user';
-- Then optionally remove default
ALTER TABLE users ALTER COLUMN role DROP DEFAULT;
```
### Adding an index
```sql
-- Use CONCURRENTLY in production (PostgreSQL)
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);
```
### Renaming a column (zero-downtime)
1. Add new column
2. Deploy code that writes to both columns
3. Backfill data from old to new
4. Switch reads to new column
5. Remove old column
### Backfill patterns
```sql
-- Batch to avoid locking
UPDATE users SET status = 'active'
WHERE id IN (
SELECT id FROM users WHERE status = 'pending'
LIMIT 10000
);
```
## Rollback Testing
Before deploying:
1. Apply migration on staging
2. Roll it back
3. Verify data integrity
4. Re-apply to confirm idempotent
## Checklist
- [ ] Migration file created with descriptive name
- [ ] DOWN migration written and tested
- [ ] Migration tested on staging DB
- [ ] Indexes added for new query columns
- [ ] NOT NULL columns have DEFAULT values
- [ ] No raw DROP TABLE (use CASCADE with caution)
- [ ] Data migrations are idempotent
- [ ] Migration runs within acceptable time (< 5 min for online)