# How to Fix Prisma Migration Conflicts

# How to Fix Prisma Migration Conflicts: A Modern Tooling Guide

## Problem

You're working in a team environment with Prisma, and suddenly your migrations won't apply. You see errors like:

```
Error: P3022 - A migration failed to apply. Read more about how to resolve migration issues in a multi-user environment: https://pris.ly/d/migrate-resolve
```

Or worse, your colleague's migration conflicts with yours, and neither of you can deploy. Your CI/CD pipeline is blocked, and you're manually resolving database state issues at 2 AM.

This is a **Prisma migration conflict**—one of the most frustrating problems in modern database development.

---

## Cause

Migration conflicts occur when:

1. **Concurrent migrations**: Two developers create migrations simultaneously without pulling the latest changes
2. **Diverged migration history**: Your local migration history differs from the remote repository
3. **Failed migrations**: A migration partially applied, leaving the database in an inconsistent state
4. **Manual database changes**: Someone modified the database directly, bypassing Prisma
5. **Environment desynchronization**: Development, staging, and production have different migration states

The root issue: **Prisma's migration system is linear and sequential**. It expects migrations to be applied in order, and any deviation causes conflicts.

---

## Fix: Step-by-Step Solutions

### Solution 1: Resolve Conflicts in Development (Recommended)

**Scenario**: You and a teammate both created migrations locally.

```bash
# 1. Check your migration status
prisma migrate status

# Output:
# Following migrations have not yet been applied:
#   20260115_add_user_roles
#   20260115_add_post_categories

# 2. Pull your teammate's changes
git pull origin main

# 3. Check the conflict
prisma migrate status

# Output:
# The following migrations have been applied to the database
# but not found in the migrations folder:
#   20260115_add_post_categories
```

**Fix approach**:

```bash
# Option A: Reset and replay (development only!)
prisma migrate reset

# This will:
# - Drop the database
# - Recreate it
# - Apply all migrations in order
# - Seed data (if seed.ts exists)

# Option B: Manually resolve (safer)
# 1. Examine both migrations
cat prisma/migrations/20260115_add_user_roles/migration.sql
cat prisma/migrations/20260115_add_post_categories/migration.sql

# 2. Merge them into a single migration
prisma migrate dev --name merge_user_and_post_changes

# 3. Delete the conflicting migration folders
rm -rf prisma/migrations/20260115_add_user_roles
rm -rf prisma/migrations/20260115_add_post_categories

# 4. Commit the merged migration
git add prisma/migrations/
git commit -m "Merge conflicting migrations"
```

### Solution 2: Resolve Failed Migrations in Production

**Scenario**: A migration partially applied and now your production database is stuck.

```bash
# 1. Check the current state
prisma migrate status

# Output:
# Migration "20260110_add_payment_table" started at 2026-01-15T10:30:00Z
# but has not finished running.

# 2. Resolve the migration
prisma migrate resolve --rolled-back 20260110_add_payment_table

# This marks the migration as rolled back without actually rolling it back
# Use this if the migration partially succeeded

# 3. Or mark it as applied if it actually completed
prisma migrate resolve --applied 20260110_add_payment_table

# 4. Verify
prisma migrate status
```

**Better approach with modern tooling (2026)**:

```bash
# Use Prisma with transaction rollback support
# In your migration file:
-- prisma/migrations/20260110_add_payment_table/migration.sql

BEGIN;

CREATE TABLE "Payment" (
  "id" TEXT NOT NULL PRIMARY KEY,
  "amount" DECIMAL(10,2) NOT NULL,
  "status" TEXT NOT NULL DEFAULT 'pending'
);

ALTER TABLE "User" ADD COLUMN "paymentId" TEXT;
ALTER TABLE "User" ADD CONSTRAINT "User_paymentId_fkey" 
  FOREIGN KEY ("paymentId") REFERENCES "Payment"("id");

COMMIT;
```

### Solution 3: Diverged Migration History

**Scenario**: Your local migrations don't match the remote repository.

```bash
# 1. Identify the divergence point
git log --oneline prisma/migrations/

# 2. Rebase your migrations
git rebase origin/main

# 3. If conflicts exist in migration files, resolve them
# Edit the conflicting migration files

# 4. Recreate your local database state
prisma migrate reset

# 5. Verify everything works
npm run test:db

# 6. Force push (only if you haven't pushed yet!)
git push origin your-branch --force-with-lease
```

### Solution 4: Manual Database Changes

**Scenario**: Someone ran raw SQL directly on the database.

```bash
# 1. Detect the drift
prisma db pull

# This introspects your database and updates schema.prisma

# 2. Create a migration to capture the changes
prisma migrate dev --name capture_manual_changes

# 3. Review the generated migration
cat prisma/migrations/20260115_capture_manual_changes/migration.sql

# 4. Commit it
git add prisma/migrations/
git commit -m "Capture manual database changes"
```

---

## Best Practices: Prevention & Modern Workflow

### 1. **Use Prisma with Git Hooks (2026 Standard)**

```bash
# .husky/pre-commit
#!/bin/sh

# Validate migrations before commit
prisma migrate status --exit-code

if [ $? -ne 0 ]; then
  echo "❌ Unapplied migrations detected. Run 'prisma migrate dev' first."
  exit 1
fi

# Validate schema syntax
prisma validate

if [ $? -ne 0 ]; then
  echo "❌ Invalid Prisma schema."
  exit 1
fi
```

### 2. **Implement CI/CD Checks**

```yaml
# .github/workflows/migrations.yml
name: Migration Validation

on: [pull_request]

jobs:
  validate:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npx prisma migrate deploy
      - run: npx prisma db push --skip-generate
      - run: npm run test:db
```

### 3. **Establish Team Conventions**

```typescript
// prisma/seed.ts - Ensure consistent seeding
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function main() {
  // Clear existing data
  await prisma.user.deleteMany();
  
  // Seed test data
  await prisma.user.create({
    data: {
      email: 'test@example.com',
      name: 'Test User',
    },
  });
}

main()
  .catch(console.error)
  .finally(() => prisma.$disconnect());
```

### 4. **Use Prisma Migrate with Staging**

```bash
# Before merging to main:
# 1. Test on staging database
DATABASE_URL="postgresql://user:pass@staging-db:5432/app_staging" \
  prisma migrate deploy

# 2. Run integration tests
npm run test:integration

# 3. Only then merge to main
git merge --no-ff feature/new-schema
```

### 5. **Document Migration Strategy**

```markdown
# Migration Guidelines

## Creating Migrations
- Always run `prisma migrate dev` locally first
- Test with `prisma migrate reset` to ensure idempotency
- Never modify generated migration files manually
- Keep migrations focused on a single logical change

## Deploying Migrations
- Use `prisma migrate deploy` in CI/CD (never `migrate dev`)
- Always backup production before deploying
- Test on staging first
- Monitor database performance after deployment

## Resolving Conflicts
- Pull latest changes before creating new migrations
- Use `prisma migrate reset` in development
- For production issues, use `prisma migrate resolve`
- Escalate to DBA if unsure
```

---

## Takeaway

Prisma migration conflicts are **preventable** with proper workflow discipline:

✅ **Do this**:
- Pull before creating migrations
- Use `prisma migrate reset` in development
- Implement pre-commit hooks
- Test migrations in CI/CD
- Document your team's migration process

❌ **Don't do this**:
- Manually edit migration files
- Modify databases outside Prisma
- Skip testing migrations
- Force-push migration changes
- Ignore `prisma migrate status` warnings

**The modern approach (2026)**: Treat migrations as immutable, version-controlled artifacts. Automate validation at every step. When conflicts occur, reset development environments and replay migrations—it's faster than manual resolution and guarantees consistency.

Your future self (and your team) will thank you.
