Skip to content
Back to skills

Database Migrations

ASecurity

Manage database schema migrations safely — Prisma Migrate, Flyway, zero-downtime migration strategies, expand-contract pattern, rollback procedures, migration testing, and production deploy sequence. Use when asked about "database migration", "Prisma migrate", "Flyway", "schema change", "add column", "rename column", "backfill data", "zero-downtime migration", "expand-contract", "migration rollback", "migrate in production", "NOT NULL column", "dropping a column safely", or "migration testing...

  • 10 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added September 9, 2026
ai-agentsjavabashsqlspringtestingdatabase

Works with

  • cli

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add yanacuti1121/Yana-AI --skill database-migrations --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Database Migrations?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Database Migrations
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/yanacuti1121-database-migrations/badge)](https://www.skillsdirectory.com/skills/yanacuti1121-database-migrations)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: database-migrations
description: >
  Manage database schema migrations safely — Prisma Migrate, Flyway,
  zero-downtime migration strategies, expand-contract pattern, rollback
  procedures, migration testing, and production deploy sequence. Use when
  asked about "database migration", "Prisma migrate", "Flyway", "schema
  change", "add column", "rename column", "backfill data", "zero-downtime
  migration", "expand-contract", "migration rollback", "migrate in production",
  "NOT NULL column", "dropping a column safely", or "migration testing".
  Do NOT use for: query optimization — see database-patterns.
  Do NOT use for: seed data for dev — separate from migration concern.
origin: yamtam-original
license: MIT © 2026 Vũ Văn Tâm
version: 1.0.0
compatibility: "Prisma ≥ 5.x, Flyway ≥ 10. PostgreSQL focus, MySQL patterns noted."
---

## When to Use

- Use when: adding/renaming/dropping columns in a live production database
- Use when: migration needs to run without taking the app offline
- Use when: a new `NOT NULL` column is needed on a table with existing rows
- Use when: auditing migration history and checking for drift
- Do NOT use for: ORM query patterns — see database-patterns
- Do NOT use for: seeding dev database — use separate seed scripts

---

## The Expand-Contract Pattern (Zero-Downtime)

```
Phase 1 — Expand (backward-compatible migration)
  → Add new column as nullable
  → Deploy app code that writes to BOTH old and new columns
  → Backfill existing rows

Phase 2 — Migrate (after all pods running new code)
  → Add NOT NULL constraint + set DEFAULT
  → Drop writes to old column

Phase 3 — Contract (after all pods no longer read old column)
  → Drop old column
```

---

## Prisma — Safe NOT NULL Column

```prisma
// ❌ Naive — breaks if table has existing rows (migration fails)
model User {
  id        String   @id
  createdAt DateTime @default(now())
  // Adding directly:
  timezone  String   // NOT NULL with no default = migration error on non-empty table
}

// ✅ Step 1: add nullable first
model User {
  timezone  String?   // nullable — migration runs safely on any table size
}
```

```bash
# Step 1: nullable column
npx prisma migrate dev --name add_user_timezone

# Step 2: backfill existing rows (SQL)
UPDATE users SET timezone = 'UTC' WHERE timezone IS NULL;

# Step 3: make NOT NULL (in a new migration)
# Modify schema: timezone String (remove ?)
npx prisma migrate dev --name make_timezone_not_null
```

---

## Prisma Migration Commands

```bash
# Dev workflow
npx prisma migrate dev               # apply pending + generate client
npx prisma migrate dev --name <name> # with explicit migration name
npx prisma migrate reset             # drop + recreate dev DB (dev only)

# CI / production
npx prisma migrate deploy            # apply pending migrations (no interactive prompts)
npx prisma migrate status            # show applied / pending migrations
npx prisma db push                   # sync schema without migration file (prototyping only)

# Production deploy sequence:
# 1. Run `prisma migrate deploy` BEFORE starting new app pods
# 2. Use rolling update after migration completes
```

---

## Flyway (Java/Spring/Multi-language)

```sql
-- V1__create_users.sql
CREATE TABLE users (
  id         UUID        PRIMARY KEY DEFAULT gen_random_uuid(),
  email      VARCHAR(255) NOT NULL UNIQUE,
  created_at TIMESTAMPTZ  NOT NULL DEFAULT now()
);

-- V2__add_user_timezone.sql  (expand)
ALTER TABLE users ADD COLUMN timezone VARCHAR(50);

-- V3__backfill_timezone.sql
UPDATE users SET timezone = 'UTC' WHERE timezone IS NULL;

-- V4__make_timezone_not_null.sql  (contract)
ALTER TABLE users ALTER COLUMN timezone SET NOT NULL,
                  ALTER COLUMN timezone SET DEFAULT 'UTC';
```

```bash
# Apply migrations
flyway -url=jdbc:postgresql://localhost/mydb -user=app -password=$DB_PASS migrate

# Validate migration checksums haven't changed
flyway validate

# Show status
flyway info
```

---

## Renaming a Column Safely

```sql
-- ❌ Immediate rename breaks code reading old name
ALTER TABLE orders RENAME COLUMN user_id TO customer_id;

-- ✅ Expand phase: add new column
ALTER TABLE orders ADD COLUMN customer_id UUID;
UPDATE orders SET customer_id = user_id;  -- backfill

-- Deploy app code writing to BOTH columns
-- Then: Contract phase (after full deploy):
ALTER TABLE orders ALTER COLUMN customer_id SET NOT NULL;
-- When all app code uses only customer_id:
ALTER TABLE orders DROP COLUMN user_id;
```

---

## Dropping a Column Safely

```sql
-- ❌ Dropping immediately — old app pods still reading that column
ALTER TABLE users DROP COLUMN legacy_flag;

-- ✅ Contract pattern:
-- 1. Deploy app code that no longer references the column
-- 2. Wait for full rollout (no pods reading the column)
-- 3. Then: mark ignored in ORM (Prisma: @ignore)
-- 4. Deploy migration that drops the column
```

```prisma
// Prisma: tell Prisma to ignore a column before dropping
model User {
  legacyFlag Boolean? @ignore   // Prisma ignores, column still exists in DB
}
// After full deploy + bake time → run DROP COLUMN migration
```

---

## Migration Testing

```bash
# Test migrations against a copy of prod data (sanitized)
pg_dump $PROD_DB --no-owner --no-acl > prod_snapshot.sql
psql $TEST_DB < prod_snapshot.sql
npx prisma migrate deploy  # run against production-like data

# Check: migration completes, app starts, smoke test passes
```

---

## Anti-Fake-Pass Rules

Before claiming a migration is safe to run in production, you MUST show:
- [ ] `NOT NULL` columns added in two phases: nullable first, then constraint
- [ ] Backfill migration is separate from schema change migration
- [ ] Production deploy sequence: `migrate deploy` → wait → rolling pod restart
- [ ] Rollback plan documented (reverse migration or data restore point)
- [ ] Migration tested against a copy of production data (not just empty dev DB)
- [ ] `prisma migrate status` / `flyway validate` shows no drift before deploy
- [ ] Column renames/drops use expand-contract — no single-step renames

Reference: `gates/anti-fake-pass-gate.md`

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.