prisma-migration-reviewer
Prisma Migration Reviewer
Before generating any output, read config/defaults.md and adapt all patterns, imports, and code examples to the user's configured stack.
Process
- Read the
migration.sqlfile (typically atprisma/migrations/<timestamp>_<name>/migration.sql). - Parse each SQL statement and classify it by risk level.
- Identify data loss risks, breaking changes, performance concerns, and missing safeguards.
- Suggest safer alternatives for dangerous operations.
- Produce a risk report with actionable recommendations.
Risk Classification
CRITICAL — Data Loss Risk
These operations destroy data. Block deployment until reviewed.
Column drop:
-- CRITICAL: Drops column and all its data
ALTER TABLE "User" DROP COLUMN "legacyId";
Safe alternative: Rename to _deprecated_legacyId, drop in a later migration after confirming no code references it.
Table drop:
-- CRITICAL: Drops table and all rows
DROP TABLE "OldAuditLog";
Safe alternative: Rename table to _archived_OldAuditLog. Drop after data is verified migrated or backed up.
Type change with data loss:
-- CRITICAL: Changing TEXT to VARCHAR(50) truncates values longer than 50 chars
ALTER TABLE "Post" ALTER COLUMN "title" TYPE VARCHAR(50);
Safe alternative: First query SELECT MAX(LENGTH(title)) FROM "Post" to verify no data exceeds the new limit.
Enum value removal:
-- CRITICAL: Rows with removed value become invalid
-- Prisma recreates enum without the old value
CREATE TYPE "Role_new" AS ENUM ('USER', 'ADMIN');
ALTER TABLE "User" ALTER COLUMN "role" TYPE "Role_new" USING ("role"::text::"Role_new");
DROP TYPE "Role";
ALTER TYPE "Role_new" RENAME TO "Role";
Safe alternative: First update all rows with the old value, then remove it.
WARNING — Potential Downtime or Breakage
NOT NULL on existing column without default:
-- WARNING: Fails if any existing rows have NULL in this column
ALTER TABLE "User" ALTER COLUMN "name" SET NOT NULL;
Safe alternative:
UPDATE "User" SET "name" = 'Unknown' WHERE "name" IS NULL;- Then
ALTER TABLE "User" ALTER COLUMN "name" SET NOT NULL;
Adding unique constraint on column with potential duplicates:
-- WARNING: Fails if duplicate values exist
ALTER TABLE "User" ADD CONSTRAINT "User_email_key" UNIQUE ("email");
Safe alternative: First query SELECT email, COUNT(*) FROM "User" GROUP BY email HAVING COUNT(*) > 1 and resolve duplicates.
Renaming column (Prisma drops and recreates):
-- WARNING: Prisma may generate DROP + ADD instead of RENAME, losing data
ALTER TABLE "User" DROP COLUMN "name";
ALTER TABLE "User" ADD COLUMN "fullName" TEXT;
Safe alternative: Use raw SQL migration with ALTER TABLE "User" RENAME COLUMN "name" TO "fullName".
Large table ALTER:
-- WARNING: On tables with millions of rows, this acquires an exclusive lock
ALTER TABLE "Event" ADD COLUMN "metadata" JSONB;
For PostgreSQL, adding a nullable column with no default is fast (no table rewrite). But adding a column with a DEFAULT requires a table rewrite on PostgreSQL < 11.
INFO — Optimization Opportunities
Missing index on foreign key:
ALTER TABLE "Post" ADD COLUMN "authorId" TEXT NOT NULL;
ALTER TABLE "Post" ADD CONSTRAINT "Post_authorId_fkey"
FOREIGN KEY ("authorId") REFERENCES "User"("id");
-- INFO: No index on "Post"."authorId" — queries filtering/joining on this FK will be slow
Recommend: CREATE INDEX "Post_authorId_idx" ON "Post"("authorId");
Missing composite index for common query patterns:
-- INFO: If queries often filter by both status and createdAt, add a composite index
CREATE INDEX "Order_status_createdAt_idx" ON "Order"("status", "createdAt");
Prisma-Specific Gotchas
- Prisma renames = drop + create: When you rename a field in
schema.prisma, Prisma generates a column drop and add, not a rename. Always usenpx prisma migrate --create-onlyand edit the SQL to useRENAME COLUMN. - Enum changes recreate the type: Any change to a Prisma enum generates a full drop-and-recreate cycle. Inspect the migration to ensure existing data is preserved.
- Optional → required: Changing a field from
String?toStringgeneratesSET NOT NULLwithout a backfill. Always add a backfill step. - Relation changes: Changing relation cardinality or required-ness can drop and recreate foreign key constraints, potentially orphaning data.
Checklist
Before approving any migration:
- No
DROP COLUMNorDROP TABLEwithout confirmed backup or rename strategy - No
SET NOT NULLwithout backfill for existing NULL rows - No
UNIQUEconstraint on columns with unverified uniqueness - All foreign key columns have indexes
- Column renames use
RENAME COLUMN, not drop + add - Enum changes preserve existing data values
- Large table operations assessed for lock duration
- Down migration strategy documented for irreversible operations
Output Format
## Migration Review: `<migration_name>`
### Summary
| Risk Level | Count |
|-----------|-------|
| 🔴 CRITICAL | N |
| 🟡 WARNING | N |
| 🔵 INFO | N |
### Findings
#### 🔴 CRITICAL: [Title]
**Statement**: `[SQL statement]`
**Risk**: [What can go wrong]
**Recommendation**: [Safer alternative with SQL]
#### 🟡 WARNING: [Title]
...
#### 🔵 INFO: [Title]
...
### Pre-Deploy Checklist
- [ ] [Actionable step based on findings]
Reference
See references/migration-risks.md for the complete catalog of dangerous operations and zero-downtime patterns.
More from nembie/claude-code-skills
code-reviewer
Automated code review for security, performance, and maintainability. Use when asked for code review, security audit, quality check, PR review, or to find issues in code.
22auth-scaffold
Scaffold authentication with Auth.js (NextAuth v5), including providers, session handling, middleware protection, and role-based access. Use when asked to set up auth, add login, protect routes, or implement authentication.
3test-generator
Generate unit and integration tests for API routes, utilities, React components, and hooks. Use when asked to generate tests, write unit tests, create integration tests, add test coverage, or test a component/route/function.
3nextjs-route-generator
Scaffold Next.js App Router API routes with Zod validation, error handling, and TypeScript types. Use when asked to create API routes, REST endpoints, CRUD operations, or scaffold a Next.js backend.
3typescript-refactorer
Identify TypeScript code smells and suggest type-safe refactoring. Use when asked to refactor, improve types, clean up TypeScript code, tighten types, reduce any usage, or improve type safety.
3prisma-query-optimizer
Analyze Prisma queries for performance issues and suggest optimizations. Use when asked to optimize, analyze, audit, or review Prisma queries, or when investigating slow database operations in a Prisma-based project.
3