This document explains the actual development workflow using prisma-strong-migrations.
┌─────────────────────────────────────────────────────────────┐
│ 1. Modify schema.prisma │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 2. Generate migration (without applying) │
│ npx prisma migrate dev --create-only --name xxx │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 3. Safety check │
│ npx prisma-strong-migrations check │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────┐
│ Warnings? │
└─────────────────┘
↓ Yes ↓ No
┌────────────────────┐ ┌────────────────────┐
│ 4a. Review warning │ │ 4b. Apply │
│ Decide action │ │ migration │
└────────────────────┘ └────────────────────┘
↓
┌────────────────────┐
│ 5. Take action │
│ - Staged migration │
│ - Add comment │
└────────────────────┘
↓
┌────────────────────┐
│ 6. Re-check │
│ → Pass │
└────────────────────┘
↓
┌────────────────────┐
│ 7. Apply │
│ migration │
└────────────────────┘
When a warning is issued, there are two approaches:
Follow the warning instructions to perform the migration safely.
Warning:
=== ❌ Dangerous operation detected ===
📍 Line 1: ALTER TABLE "users" DROP COLUMN "name"
Removing a column may cause errors in your application.
💡 Recommended approach:
1. Remove all usages of 'name' field from your code
2. Run 'npx prisma generate' to update Prisma Client
3. Deploy the code changes
4. Then apply this migration
Action:
- Remove references to
namefield from application code - Run
npx prisma generate - Deploy code changes
- Apply the migration
# After code changes, apply migration
npx prisma migrate devIf you understand the risks and want to proceed, add a comment.
-- prisma-strong-migrations-disable-next-line <rule_name>
-- Reason: <reason>
<SQL statement>-- prisma-strong-migrations-disable-next-line remove_column
-- Reason: This is a new table with no production data yet
ALTER TABLE "temp_users" DROP COLUMN "name";-- prisma-strong-migrations-disable-next-line remove_column rename_column
-- Reason: Refactoring unused legacy table
ALTER TABLE "legacy_users" DROP COLUMN "old_name";-- prisma-strong-migrations-disable-next-line
-- Reason: Emergency hotfix, reviewed by @senior-dev
ALTER TABLE "users" DROP COLUMN "name";Some rules can automatically rewrite the migration SQL to a safer equivalent. Use --fix to apply these fixes without editing the file manually.
| Rule | What --fix does |
|---|---|
addIndex |
CREATE INDEX → CREATE INDEX CONCURRENTLY + adds disable-transaction header |
removeIndex |
DROP INDEX → DROP INDEX CONCURRENTLY + adds disable-transaction header |
addForeignKey |
Adds NOT VALID + appends VALIDATE CONSTRAINT as a second statement |
addCheckConstraint |
Adds NOT VALID + appends VALIDATE CONSTRAINT as a second statement |
setNotNull |
Expands into: ADD CONSTRAINT … CHECK NOT VALID → VALIDATE CONSTRAINT → SET NOT NULL → DROP CONSTRAINT |
addUniqueConstraint |
Replaces with CREATE UNIQUE INDEX CONCURRENTLY + ADD CONSTRAINT … USING INDEX + adds disable-transaction header |
Rules that require application code changes (removeColumn, renameColumn, etc.) or human-supplied values cannot be auto-fixed.
# 1. Modify schema.prisma, then:
npx prisma-strong-migrations migrate dev --fix
# → Fixes are written to the migration SQL file.
# The migration is NOT applied yet.
# 2. Review the rewritten SQL, then apply:
npx prisma-strong-migrations migrate devImportant:
--fixis fix-only. Even if all errors were resolved, the migration is never applied in the same run. Always re-run without--fixto apply.
# Fix all auto-fixable issues across all migration files:
npx prisma-strong-migrations check --fix
# Fix a specific migration file:
npx prisma-strong-migrations check prisma/migrations/20240320_add_index/migration.sql --fix# After schema.prisma change, prisma-strong-migrations generates and checks:
npx prisma-strong-migrations migrate dev --fix
# Output:
# ✔ Auto-fixed 1 issue(s) in prisma/migrations/20240320_.../migration.sql
# ✅ Auto-fix applied. Run the same command again (without --fix) to apply the migration.
# The SQL is now:
# -- prisma-migrate-disable-next-transaction
# CREATE INDEX CONCURRENTLY "User_email_idx" ON "User"("email");
# Review and apply:
npx prisma-strong-migrations migrate devIf a migration contains both auto-fixable and non-fixable errors, --fix applies what it can and then exits with an error listing the remaining issues. Edit those manually before re-running.
# 1. Remove field from schema.prisma
# model User {
# id Int @id
# // name String ← removed
# email String
# }
# 2. Generate migration
npx prisma migrate dev --create-only --name remove_user_name
# 3. Check
npx prisma-strong-migrations check
# → remove_column warning
# 4. Choose approach
# A) Staged migration: Remove references from code → Deploy → Migration
# B) Skip: Add comment
# For 4B: Add comment
cat >> prisma/migrations/20240320_remove_user_name/migration.sql << 'EOF'
-- prisma-strong-migrations-disable-next-line remove_column
-- Reason: Field unused, confirmed no references in codebase (grep -r "user.name" returned 0 results)
EOF
# 5. Re-check
npx prisma-strong-migrations check
# → Pass
# 6. Apply migration
npx prisma migrate dev# 1. Add index to schema.prisma
# model User {
# id Int @id
# email String
# @@index([email]) ← added
# }
# 2. Generate migration
npx prisma migrate dev --create-only --name add_user_email_index
# 3. Check
npx prisma-strong-migrations check
# → add_index warning (non-CONCURRENTLY)
# 4. Manually edit migration.sql
vim prisma/migrations/20240320_add_user_email_index/migration.sql
# Before:
# CREATE INDEX "User_email_idx" ON "User"("email");
# After:
# CREATE INDEX CONCURRENTLY "User_email_idx" ON "User"("email");
# 5. Re-check
npx prisma-strong-migrations check
# → Pass
# 6. Apply migration
npx prisma migrate dev# 1. Add relation to schema.prisma
# model Post {
# id Int @id
# userId Int
# user User @relation(fields: [userId], references: [id]) ← added
# }
# 2. Generate migration
npx prisma migrate dev --create-only --name add_post_user_fk
# 3. Check
npx prisma-strong-migrations check
# → add_foreign_key warning (no NOT VALID)
# 4. Manually edit migration.sql and split into two migrations
# Migration 1: prisma/migrations/20240320_add_post_user_fk/migration.sql
# ALTER TABLE "Post"
# ADD CONSTRAINT "Post_userId_fkey"
# FOREIGN KEY ("userId") REFERENCES "User"("id")
# NOT VALID;
# Migration 2: prisma/migrations/20240321_validate_post_user_fk/migration.sql
# ALTER TABLE "Post"
# VALIDATE CONSTRAINT "Post_userId_fkey";
# 5. Re-check
npx prisma-strong-migrations check
# → Pass
# 6. Apply migration
npx prisma migrate devname: Migration Check
on:
pull_request:
paths:
- "prisma/schema.prisma"
- "prisma/migrations/**"
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Vite+
uses: voidzero-dev/setup-vp@v1
with:
node-version: "22"
cache: true
- name: Install dependencies
run: vp install
- name: Check migrations
run: npx prisma-strong-migrations checkWhen check fails, you can also add a comment to the PR:
- name: Check migrations
id: check
run: |
npx prisma-strong-migrations check --format json > report.json
echo "result=$(cat report.json)" >> $GITHUB_OUTPUT
continue-on-error: true
- name: Comment on PR
if: steps.check.outcome == 'failure'
uses: actions/github-script@v7
with:
script: |
const report = JSON.parse('${{ steps.check.outputs.result }}');
const body = `## ⚠️ Migration Safety Check Failed
${report.errors.map(e => `- **${e.code}**: ${e.message}`).join('\n')}
Please review the warnings and either:
1. Follow the recommended safe approach
2. Add a disable comment with a reason
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});# ✅ Good: Separate generation and application
npx prisma migrate dev --create-only --name xxx
npx prisma-strong-migrations check
npx prisma migrate dev
# ❌ Bad: Direct application (cannot check)
npx prisma migrate dev --name xxx-- ✅ Good: Clear reason
-- prisma-strong-migrations-disable-next-line remove_column
-- Reason: Column deprecated in v2.0, no references found (verified with grep)
ALTER TABLE "users" DROP COLUMN "legacy_field";
-- ❌ Bad: No reason
-- prisma-strong-migrations-disable-next-line remove_column
ALTER TABLE "users" DROP COLUMN "legacy_field";Prioritize using the recommended safe approach over skipping warnings.
Commit prisma-strong-migrations.config.js to the repository so the entire team uses the same rules.
// prisma-strong-migrations.config.js
module.exports = {
// Project-specific settings
customRulesDir: "./prisma-strong-migrations-rules",
};Check migration files for dangerous operations.
# Check all migrations in migrationsDir
npx prisma-strong-migrations check
# Check a specific migration file
npx prisma-strong-migrations check prisma/migrations/20240320_add_index/migration.sql| Option | Description |
|---|---|
-f, --format <format> |
Output format: console (default) or json |
-c, --config <path> |
Path to config file (default: prisma-strong-migrations.config.js) |
--no-fail |
Always exit with code 0, even if errors are found |
--fix |
Automatically rewrite auto-fixable issues in the SQL files |
Outputs a JSON object suitable for CI tooling:
{
"errors": [
{
"ruleName": "addIndex",
"severity": "error",
"migrationPath": "prisma/migrations/20240320_.../migration.sql",
"line": 3,
"message": "...",
"suggestion": "..."
}
],
"warnings": [],
"totalErrors": 1,
"totalWarnings": 0
}Useful when you want to surface issues as information without blocking CI:
# Report issues but never fail the pipeline
npx prisma-strong-migrations check --no-failCreate a migration with --create-only, check it, then apply if safe.
npx prisma-strong-migrations migrate dev| Option | Description |
|---|---|
--name <name> |
Name passed to prisma migrate dev |
--schema <path> |
Path to schema.prisma, passed to Prisma |
-c, --config <path> |
Path to config file |
--fix |
Auto-fix issues, then exit without applying (re-run without --fix to apply) |
--force |
Skip all safety checks — for local dev environment setup only |
Any unknown options are forwarded to prisma migrate dev.
Check all migrations, then run prisma migrate deploy if all checks pass.
npx prisma-strong-migrations migrate deploy| Option | Description |
|---|---|
-c, --config <path> |
Path to config file |
--force |
Skip all safety checks — for local dev environment setup only |
Any unknown options are forwarded to prisma migrate deploy.
Interactive setup wizard. Run once when introducing the tool to a project.
npx prisma-strong-migrations initWhat it does:
- Creates
prisma-strong-migrations.config.jsin the current directory with all available options and their defaults - Scans
package.jsonscripts forprisma migrate dev/prisma migrate deployand interactively offers to replace them withprisma-strong-migrations migrate dev/prisma-strong-migrations migrate deploy
Generate a custom rule template.
npx prisma-strong-migrations init-rule my-rule-nameCreates ./prisma-strong-migrations-rules/my-rule-name.js with a skeleton rule implementation. Edit the file to implement detect, message, and suggestion.
See README.md for the full custom rules guide.
When introducing prisma-strong-migrations to an already-running application, the first local environment setup presents a specific challenge:
- Many migration files exist on disk (e.g., 50+ files)
- The local database is clean (no migration history)
- All those files are flagged as "pending" and checked
- Old migrations trigger errors even though they're safely running in production
Use --force to skip all safety checks and apply migrations directly:
# Local dev environment setup — bypass all checks
npx prisma-strong-migrations migrate dev --force
# Or with deploy:
npx prisma-strong-migrations migrate deploy --forceA warning is printed when --force is used:
⚠️ --force: Safety checks skipped. Use only for local dev environment setup.
After the initial setup is done, run without --force as usual for day-to-day development.
Important: Never use
--forcein CI/CD pipelines or production deployments. It is intended exclusively for local development environment bootstrap.
- Ensure the same Node.js version is used
- Check if config file is committed
- Verify migration files are committed
If the SQL parser fails:
- Check if the SQL syntax is valid
- Some PostgreSQL-specific syntax may not be supported
- Report issues with the SQL that failed
If a warning is incorrect:
- Check if the rule is appropriate for your use case
- Consider disabling the rule in config
- Report as an issue if it's a bug