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.emailalready allow nulls? How many nulls if we add NOT NULL?” - “Does this
ADD COLUMNduplicate a column that exists under another name?” - “Are there orphan
order_itemsthat would break a new FK?” - “Is there already an index that makes this
CREATE INDEXredundant?”
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
- Staging DB connected (Cursor is ideal; Claude works too)
- Synra (or similar) read-only — writes blocked
- Open the migration file in the editor (Cursor) or paste its contents into chat
- 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:
- Explore an Unfamiliar Database With AI — map schema before you change it
- Find Missing Indexes With AI — when the migration is an index
- Why Read-Only AI Database Access Matters — keep APPLY out of the chat connector
- Connect Cursor to PostgreSQL — IDE setup
- Connect Cursor to Neon — branch per PR
- How to Verify AI Answers About Your Database — trust but check counts
- Staging First — environment ladder