seb1n/database-migration
Create, execute, and roll back versioned database schema migrations using tools like Alembic, Prisma Migrate, Flyway, and Knex.
npx skills add https://github.com/seb1n/awesome-ai-agent-skills --skill database-migration
This skill enables an AI agent to manage versioned database schema changes through migration frameworks. The agent creates forward and rollback migration scripts, handles data backfills during schema changes, ensures zero-downtime deployments with safe migration patterns, and integrates migration workflows into CI/CD pipelines. It supports major tools including Alembic (Python/SQLAlchemy), Prisma Migrate (TypeScript/Node), Flyway (Java/SQL), and Knex (JavaScript).
Describe the schema change you need (e.g., "add a phone_number column to the users table") and specify which migration framework your project uses. The agent will generate the migration file with both upgrade and downgrade logic, provide instructions to apply it, and advise on safe deployment strategies for production.
Request: Add a display_name column to the users table and backfill it by concatenating first_name and last_name.
Generate the migration:
alembic revision --autogenerate -m "add_display_name_to_users"
Migration file (versions/20250115_add_display_name_to_users.py):
"""add display_name to users
Revision ID: a1b2c3d4e5f6
Revises: 9z8y7x6w5v4u
Create Date: 2025-01-15 10:30:00.000000
"""
from alembic import op
import sqlalchemy as sa
revision = "a1b2c3d4e5f6"
down_revision = "9z8y7x6w5v4u"
branch_labels = None
depends_on = None
def upgrade():
# Phase 1: Add the column as nullable (safe, no locks on reads)
op.add_column("users", sa.Column("display_name", sa.String(300), nullable=True))
# Phase 2: Backfill existing rows
users = sa.table(
"users",
sa.column("id", sa.Integer),
sa.column("first_name", sa.String),
sa.column("last_name", sa.String),
sa.column("display_name", sa.String),
)
op.execute(
users.update().values(
display_name=sa.func.concat(
users.c.first_name, " ", users.c.last_name
)
)
)
# Phase 3: Set NOT NULL after backfill is complete
op.alter_column("users", "display_name", nullable=False)
def downgrade():
op.drop_column("users", "display_name")
Apply and verify:
alembic upgrade head
alembic current # Confirms: a1b2c3d4e5f6 (head)
Request: Add a Review model linked to User and Product in a Prisma project.
Update prisma/schema.prisma:
model Review {
id Int @id @default(autoincrement())
rating Int @db.SmallInt
comment String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userId Int
productId Int
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
@@unique([userId, productId])
@@index([productId])
@@index([rating])
}
Generate and apply the migration:
npx prisma migrate dev --name add_reviews_table
Generated SQL (prisma/migrations/20250115_add_reviews_table/migration.sql):
CREATE TABLE "Review" (
"id" SERIAL NOT NULL,
"rating" SMALLINT NOT NULL,
"comment" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"userId" INTEGER NOT NULL,
"productId" INTEGER NOT NULL,
CONSTRAINT "Review_pkey" PRIMARY KEY ("id")
);
CREATE INDEX "Review_productId_idx" ON "Review"("productId");
CREATE INDEX "Review_rating_idx" ON "Review"("rating");
CREATE UNIQUE INDEX "Review_userId_productId_key" ON "Review"("userId", "productId");
ALTER TABLE "Review" ADD CONSTRAINT "Review_userId_fkey"
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE;
ALTER TABLE "Review" ADD CONSTRAINT "Review_productId_fkey"
FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE;
ADD COLUMN ... DEFAULT ... NOT NULL (lock-free in PostgreSQL 11+) or add as nullable, backfill in batches, then set NOT NULL.op.alter_column() in Alembic or raw ALTER TABLE ... RENAME COLUMN to perform a true rename. Verify the generated migration before applying.Take seb1n/database-migration from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npx.
Without those the skill loads but fails at the first command.