# Stop Cursor from running prisma migrate reset on the wrong database

> Source: <https://dev.to/labyrinthlab/stop-cursor-from-running-prisma-migrate-reset-on-the-wrong-database-3pch>
> Published: 2026-10-08 13:15:03+00:00

Here is the failure mode, step by step.

`db push` to try something.`prisma migrate dev`, which reports drift and says the database needs a reset.` prisma migrate reset --force`.`.env` still has the staging or production `DATABASE_URL` you pasted in last week to debug something.
`migrate reset` drops the database (or schema), recreates it and applies every migration. On Prisma 6 and earlier it also runs your seed. On dev that's a fine way to get unstuck. Anywhere else it's a restore-from-backup afternoon.

`postgresql://app@db.internal:5432/app` says "this one has customers in it."`--force`.
Since Prisma ORM 6.15.0, the CLI looks for environment variables that coding agents set (for Cursor, `CURSOR_AGENT`). When it finds one, `prisma migrate reset` stops with an error telling the agent to explain what it was about to do and ask you first. The agent can only rerun it with `PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION` set to the exact text of your consent message. The same check covers `prisma db push --force-reset`, and since 7.9.0, `prisma db push --accept-data-loss`. That is a good backstop. It still leaves gaps:

`db execute`, or Drizzle.` migrate deploy`.
You want the agent checking the target before it reaches that prompt.

The cheapest fix isn't a rule. Don't keep prod or staging URLs in the `.env` your editor loads, and give your day-to-day role no `DROP` rights on shared databases. Rules steer the agent. Missing credentials can't be talked around.

Cursor loads project rules from `.cursor/rules/*.mdc`. Each file is markdown with a small frontmatter block:

`description`: what the rule is for.` globs`: file patterns that pull the rule in.` alwaysApply`: `true` attaches it to every agent request.
Install:

```
mkdir -p .cursor/rules
# save the rule below as .cursor/rules/migration-checklist.mdc
```

Then open Customize in the sidebar, go to Rules, and confirm it's listed. Test with "migrations are out of sync, reset the db." A working setup asks about the target database instead of running a command.

Here is the full rule. It's one of four in our Schema Migration Guard pack, and this one is free. Copy it as is or trim what you don't need.

```
---
description: "Pre-push and pre-migrate checklist for database schema changes"
globs: ["**/migrations/**", "**/prisma/migrations/**", "**/drizzle/**"]
alwaysApply: true
---

# Migration Checklist

## PRE-MIGRATION CHECKLIST

Before running any migration command, verify:

### 1. Environment Check
- [ ] **Which database am I targeting?** (dev/staging/prod)
- [ ] **Is this the correct connection string?** Check `DATABASE_URL` or config
- [ ] **Do I have a backup?** (Required for staging/prod)

### 2. Schema Review
- [ ] **Did I read the generated SQL?** (Not just the schema diff)
- [ ] **Are there destructive operations?** (DROP, TRUNCATE, DELETE)
- [ ] **Will existing data survive?** (Type changes, NOT NULL additions)
- [ ] **Are indexes appropriate?** (Not missing, not excessive)

### 3. Data Considerations
- [ ] **Will this migration lock tables?** (Large tables = long locks)
- [ ] **Is there a data migration needed?** (Backfill, transform)
- [ ] **What's the rollback plan?** (Reverse migration or restore)

## PRE-PUSH CHECKLIST

Before pushing migration files to the repository:

### 1. File Hygiene
- [ ] **Migration file is committed** (Not in .gitignore)
- [ ] **Migration name is descriptive** (Not "migration_1" or "fix")
- [ ] **No sensitive data in migration** (No hardcoded credentials)
- [ ] **SQL is reviewed and correct** (Read the actual file)

### 2. Local Verification
- [ ] **Migration applies cleanly locally** (Tested on fresh DB)
- [ ] **App still works after migration** (Run tests)
- [ ] **Migration is idempotent or guarded** (Won't fail if run twice)

### 3. Team Coordination
- [ ] **No conflicting migrations from teammates** (Pull latest first)
- [ ] **Migration order is correct** (Timestamp/sequence is right)
- [ ] **Breaking changes documented** (If API changes needed)

## PRODUCTION DEPLOYMENT CHECKLIST

Before deploying migrations to production:

### 1. Pre-Deploy
- [ ] **Database backup completed** (Verified, not just scheduled)
- [ ] **Maintenance window scheduled** (If needed for locks)
- [ ] **Rollback plan documented** (Restore steps or reverse migration)
- [ ] **Team notified** (On-call aware of deployment)

### 2. During Deploy
- [ ] **Monitor migration progress** (Watch for locks, errors)
- [ ] **Check application health** (Errors, latency spikes)
- [ ] **Have rollback ready** (Don't walk away mid-migration)

### 3. Post-Deploy
- [ ] **Verify migration status** (`migrate status` shows clean)
- [ ] **Test affected features** (Not just "app starts")
- [ ] **Monitor for delayed issues** (Slow queries, missing data)

## DESTRUCTIVE OPERATION ESCALATION

When a migration contains destructive SQL:

### Level 1: Column Drop
**Required:** Read SQL twice, confirm column name, verify no app references.
```
Migration contains: ALTER TABLE "users" DROP COLUMN "legacy_field"
Confirm: "I verified no code references legacy_field. Drop it."
```

### Level 2: Table Drop
**Required:** Level 1 + verify no foreign keys, confirm data is backed up or worthless.
```
Migration contains: DROP TABLE "temp_imports"
Confirm: "I verified temp_imports has no important data and no references. Drop it."
```

### Level 3: Data Deletion
**Required:** Level 2 + explicit row count awareness, backup verification.
```
Migration contains: DELETE FROM "audit_logs" WHERE created_at < '2023-01-01'
Confirm: "I understand this deletes ~50,000 rows. Backup verified. Proceed."
```

### Level 4: Full Reset
**Required:** All above + explicit database name confirmation.
```
Command: prisma migrate reset / drizzle-kit push --force
Confirm: Type the database name to confirm: ___________
```

## COMMON MISTAKES TO CATCH

### Prisma-Specific
- `migrate dev` on non-dev database
- Editing migration SQL after it's been applied elsewhere
- `@@map` or `@map` changes that rename without data migration
- Enum changes that remove values still in use

### Drizzle-Specific
- `push` instead of `generate` + `migrate` on persistent DB
- Missing `NOT NULL` default for existing rows
- `drizzle-kit drop` on migration that's already deployed elsewhere
- Introspect overwriting intentional schema divergence

### Universal
- Changing column type without considering data truncation
- Adding unique constraint to column with duplicate data
- Removing column that's still referenced in app code
- Deploying migration before code that handles new schema

## ROLLBACK REFERENCE

### Prisma Rollback Options
``` bash
# Mark migration as rolled back (doesn't undo DB changes)
prisma migrate resolve --rolled-back [migration_name]

# Actual rollback requires manual SQL or restore
pg_restore -d mydb backup.dump
```

### Drizzle Rollback Options
``` bash
# No built-in rollback: write reverse migration
drizzle-kit generate  # Create new migration to undo

# Or restore from backup
pg_restore -d mydb backup.dump
```

## QUICK COMMANDS REFERENCE

### Prisma
``` bash
prisma migrate status          # Check pending migrations
prisma migrate dev             # Dev: generate + apply
prisma migrate deploy          # Prod: apply pending only
prisma migrate diff            # Preview changes
prisma migrate resolve         # Fix migration state
```

### Drizzle
``` bash
drizzle-kit status             # Check state
drizzle-kit generate           # Generate SQL files
drizzle-kit migrate            # Apply migrations
drizzle-kit push               # Direct push (dev only)
drizzle-kit introspect         # Generate schema from DB
The part doing the work for `migrate reset` is **Level 4: Full Reset**: the agent has to name the database first. The rest keeps it reading generated SQL instead of trusting the schema diff, which is where dropped columns hide. Commit `.cursor/rules/` so the whole team gets it.

With Drizzle the risky command is usually `drizzle-kit push`. It applies your schema straight to the database with no migration file, and `--force` auto-approves data-loss statements. That's fine against a throwaway local database. Against anything persistent, use the tracked flow:

```
drizzle-kit generate   # writes SQL to your migrations folder
# read the SQL
drizzle-kit migrate    # applies it
```

Also check `dbCredentials.url` in `drizzle.config.ts`. If it reads `process.env.DATABASE_URL`, it has the same "which `.env` is loaded?" problem. The checklist above already matches `**/drizzle/**` and flags `push` on a persistent database.

A rule is prose, so a determined agent can still ignore it. For a hard stop, add a Cursor hook. Project hooks live in `.cursor/hooks.json`, and a `beforeShellExecution` hook runs before each shell command the agent wants to execute. Its `matcher` is a regex tested against the full command string:

```
{
  "version": 1,
  "hooks": {
    "beforeShellExecution": [
      {
        "command": ".cursor/hooks/block-destructive.sh",
        "matcher": "migrate reset|--force-reset|--accept-data-loss|drizzle-kit push.*--force"
      }
    ]
  }
}
```

The script only runs for matching commands, so it can simply refuse:

``` bash
#!/bin/bash
# .cursor/hooks/block-destructive.sh
cat > /dev/null
exit 2
```

Make it executable with `chmod +x .cursor/hooks/block-destructive.sh`. Exit code 2 blocks the command, the same as returning `"permission": "deny"` in the hook's JSON output. Other non-zero exit codes fail open and let the command through, and project hooks only run in a trusted workspace. Run those commands yourself, in your own terminal, when you mean it.

Written with AI assistance and checked against the Prisma and Cursor docs.

Disclosure: Schema Migration Guard is our paid pack. It adds Prisma, Drizzle, and destructive-SQL review rules on top of this checklist: [https://labyrinth63.gumroad.com/l/kbhasc?utm_source=devto&utm_medium=organic&utm_campaign=guard_v2](https://labyrinth63.gumroad.com/l/kbhasc?utm_source=devto&utm_medium=organic&utm_campaign=guard_v2)
