Back to Blog

Check a Migration Against Your Database With AI

Before you merge a migration, ask Cursor or Claude to compare it to staging: nulls, type mismatches, missing indexes, row counts that would break a NOT NULL. Read-only prompts included.

Migration looks fine in GitHub. Staging has three years of messy rows. NOT NULL is about to meet reality.

Use Cursor or Claude before apply: compare the migration to live staging and flag likely failures. Don’t let chat run migrate up on production.

Read-only only — why that matters. Staging first. Still learning the schema? Explore it first.

What AI is good at in this workflow

  • “Does users.email already allow nulls? How many nulls if we add NOT NULL?”
  • “Does this ADD COLUMN duplicate a column that exists under another name?”
  • “Are there orphan order_items that would break a new FK?”
  • “Is there already an index that makes this CREATE INDEX redundant?”

What AI is bad at (still your job)

  • Lock time on a huge table in production
  • Expand/contract ordering across multiple deploys
  • Whether the app code will deploy in the right order
  • Applying the migration (CI / DBA path)

Setup

  1. Staging DB connected (Cursor is ideal; Claude works too)
  2. Synra (or similar) read-only — writes blocked
  3. Open the migration file in the editor (Cursor) or paste its contents into chat
  4. Know one truth: roughly how big the hot table is

Prompt: preflight a migration

You have read-only database access. Do not run DDL or DML.

Here's a migration (or: read the migration file I have open).
Compare it to the live staging schema:

1. List every object it touches (tables/columns/indexes/constraints)
2. For each risky change (NOT NULL, FK, unique, drop column, type change):
   - run SELECTs to estimate failure (null counts, orphan counts, duplicate keys)
3. Say PASS / RISK / FAIL for applying this to staging as-is
4. Show the SQL you ran

If the migration drops or renames something, check for app-facing columns
that still look in use (don't guess code — note what the DB shows).

Prompt: NOT NULL specifically

This migration adds NOT NULL to <table.column>.
On staging, count nulls and total rows.
If nulls > 0, draft a backfill SELECT (read-only) that shows sample ids
— do not UPDATE. Recommend expand/contract steps in prose.

Prompt: new foreign key

This migration adds FK from <child.col> to <parent.col>.
Count child rows with no matching parent.
Show a few example child ids if orphans exist (no PII columns).

Prompt: after you apply on staging (still read-only)

The migration was applied on staging by our migrate tool.
Verify:
- expected columns/indexes exist
- row counts on touched tables look sane vs before (I can paste before counts)
Report anything unexpected. SELECT only.

Cursor-specific tip

@-mention the migration file and the MCP server so Composer doesn’t freestyle against the wrong DB. Name Synra connections staging-app, never bare prod.

If Composer proposes UPDATE to “fix nulls,” let read-only reject it. Backfills belong in a deliberate migration or script, not a chat side effect.

When the check says RISK

  • Nulls exist → backfill migration first, or drop NOT NULL from this PR
  • Orphans exist → clean data or don’t add the FK yet
  • Staging empty → refresh staging; don’t ship blind
  • AI and your gut disagree → run the same SELECT in psql (verify)

Hard no

  • “Just apply this on prod for me” in chat
  • Using the app owner role so the agent can migrate
  • Skipping staging because “it’s only an index”

Inspect on staging, apply through CI. AI shortens the inspect step.

Staging + read-only: mcpserver.design (7-day Solo trial). Preflight prompt before the next risky NOT NULL.

Related reading: