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

3.1 KiB

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)

npx prisma migrate dev --name add_user_role
  • Edit schema.prisma → generate migration → review → apply
  • Always check the generated SQL

Drizzle (TypeScript)

npx drizzle-kit generate:pg --name add_user_role
  • Migration files are TypeScript
  • Easier to review and modify than raw SQL

Django (Python)

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)

alembic revision --autogenerate -m "add_user_role"
alembic upgrade head
  • Review auto-generated migrations carefully
  • Add missing operations manually

Go (goose, golang-migrate)

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

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

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

-- 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)