Home
Engineering team planning a safe database migration with AI coding agents and a verified rollout checklist
Coding

AI Coding Agents for Database Migrations in 2026: Cursor, Copilot, Windsurf, Continue, and Devin Without Schema Surprises

Published:

Last updated: August 4, 2026 · Category cluster: AI coding tools

A database migration can pass every generated test and still lock your busiest table at noon. The code agent may write valid SQL, update the application model, and produce a tidy pull request. It cannot infer your real write rate, the oldest app version still serving traffic, a replica that lags during backfills, or the on-call rule that forbids a certain DDL operation during business hours. Those facts live outside the prompt unless your team puts them there.

This guide is for engineering managers, database owners, platform teams, and product developers who want AI coding agents to help with schema changes without treating production data as a coding sandbox. We compare Cursor, GitHub Copilot, Windsurf, Continue, and Devin by the role each can play in planning, editing, testing, and reviewing a migration.

The operating rule is strict: let an agent prepare evidence, never let it invent production facts. A safe migration separates schema compatibility, data movement, application rollout, observability, and cleanup. Each phase has an owner and a rollback path. The agent can speed up repetitive work inside that frame, but a human database owner decides whether and when a production command runs.

Key Takeaways
  • Production facts belong in a change packet — record engine version, table size, traffic shape, compatibility window, lock limits, owners, and rollback before asking for SQL.
  • Expand first, migrate second, contract last — old and new application versions must coexist while data moves and traffic changes.
  • Backfills are services, not scripts — require bounded batches, checkpoints, idempotency, rate controls, progress metrics, and a tested stop switch.
  • Generated SQL receives engine-specific review — syntax validity says little about locks, rewrites, replicas, transaction logs, or online behavior.
  • Agents do not receive production credentials — they work against fixtures or disposable copies and deliver a pull request plus evidence for human approval.

Why valid migration code still fails in production

Migration risk comes from state, time, and mixed versions. Ordinary application code often moves from old release to new release as one logical event. A database change sits underneath several app instances, background workers, analytics jobs, exports, mobile clients, and replicas that do not all change together. For a period, two or more versions read and write the same tables. SQL that is correct for the final release may be incompatible during that overlap.

Locks are the first hidden edge. A statement that finishes instantly on an empty test database can wait behind a long transaction in production. Once it obtains a strong lock, unrelated requests queue behind it. The exact behavior depends on the database engine, release, table definition, and operation. PostgreSQL’s ALTER TABLE documentation is a better authority than a model’s recollection, and your current engine manual should be linked directly in the change packet.

Table rewrites create a second edge. Adding a field, changing a type, rebuilding an index, or changing a constraint can scan or rewrite far more data than the diff suggests. That work produces I/O, transaction log volume, replication pressure, and storage growth. A staging table with ten thousand rows will not reveal what happens on a primary holding two billion rows. An agent cannot estimate the cost without measured table and index data.

Application compatibility is just as important. Imagine renaming customer_name to display_name. If the migration drops the old field before every worker updates, old code fails. If both fields remain but writers update only one, they diverge. If a dual-write path retries after a timeout, it may apply a change twice. The schema operation is one line; the safe rollout is a sequence of releases.

Backfills add operational load. A generated loop may update every row in one transaction, hold locks for minutes, fill logs, and make cancellation painful. Even a batched job can overload the primary if it ignores replica delay and request latency. “The query completes” is not acceptance. The requirement is that it advances at a controlled rate, can resume after interruption, and leaves normal traffic within agreed limits.

Finally, cleanup can break forgotten consumers. BI queries, support scripts, CSV exports, old mobile releases, and disaster-recovery jobs often depend on fields that no code search finds. Before deletion, use query logs, ownership records, dashboards, and a deprecation period. AI code search helps find repository references; it does not prove the absence of runtime consumers.

Developer reviewing database metrics and migration evidence before changing a production schema

Build a migration change packet before prompting an agent

A migration change packet is the compact source of truth for the task. Keep it in the issue or beside the migration code. Start with the business reason and observable end state. “Replace integer status with text” is a solution. “Support five new order states while old workers continue to process the current four for seven days” explains the compatibility need.

Record the engine, exact major version, migration framework, deployment method, and transaction behavior. Link the applicable vendor docs. Include measured table row count, on-disk size, index size, daily growth, peak read and write rates, longest normal transaction, replica setup, available headroom, and backup expectations. If a number is unknown, mark it unknown and assign discovery. Do not let the agent fill the blank with a typical value.

Map every reader and writer you know. That includes API services, workers, scheduled jobs, event consumers, analytics, support tools, imports, exports, and older client versions. For each one, state the release order and compatibility window. The list often exposes that the task is not one migration but three application changes surrounding a data move.

Add explicit constraints: maximum lock wait, acceptable latency increase, backfill rate ceiling, replica-lag threshold, maintenance windows, disallowed operations, and required approvers. Name the production executor. In a good process, the coding agent can create migration files and run tests in a disposable environment, but it cannot connect to production or schedule the rollout.

Define evidence before code. Ask for an old-schema/new-app test, a new-schema/old-app test where coexistence is required, upgrade from a realistic prior snapshot, downgrade or forward-fix plan, query plan for each batch, lock behavior test, disk estimate, and backfill resume test. Some engines make rollback of a large data change less safe than a forward fix; the packet should state which strategy the team uses.

End with stop conditions. Examples include an unexpected table rewrite, a lock above the agreed duration, replica lag beyond the threshold, error-rate growth, a missing consumer owner, changed query plan, or a backfill estimate outside the window. Stop conditions turn “watch it carefully” into an action the release owner can execute.

Cursor, Copilot, Windsurf, Continue, and Devin compared for migration work

Tool Best migration role Useful strength Required boundary
Cursor Interactive repository tracing and phased edits Codebase context, project rules, planning, and multi-file changes close to the developer. Read-only production facts; approved paths and local commands; human review of every DDL statement.
GitHub Copilot IDE suggestions, tests, and GitHub pull-request work Fits existing editors, repository instructions, issues, CI, and code ownership. Normal branch protection remains; generated suggestions never equal database approval.
Windsurf Multi-step implementation in a disposable environment Can edit code, run migration tests, respond to failures, and prepare a reviewable diff. No production network; command allowlist; pause on schema or scope surprises.
Continue Team-controlled model and private code workflows Open configuration, provider choice, local-model options, and shared team rules. Benchmark the chosen model on your engine and framework; local processing does not prove SQL safety.
Devin Delegated preparation of a tightly specified migration ticket Persistent sandbox and pull-request delivery can suit fixtures, backfill code, tests, and docs. No production execution; exact acceptance tests; database owner signs off and runs the release.

Cursor works well when a database-aware developer wants to trace model definitions, repositories, jobs, API contracts, and migration conventions while staying close to the diff. Ask it to cite files for every reader and writer it finds. Treat the map as a candidate list, then compare it with runtime query logs and owner knowledge.

GitHub Copilot is a natural option for teams that already put migrations through GitHub issues, pull requests, CI, CODEOWNERS, and protected branches. It can draft framework-specific files and compatibility tests without creating a separate operating lane. Keep database review explicit: repository approval and a green unit suite cannot predict production lock cost.

Windsurf can handle a longer local loop: create the additive schema change, update a writer, generate a backfill, start a disposable database, run upgrade tests, and repair ordinary failures. That autonomy needs a narrow environment. Seeded test data is acceptable; copied customer data, production credentials, and unrestricted cloud commands are not.

Continue is worth comparing when model routing, source control, or local inference matters. A team may connect an approved provider or local model and version its instructions. Test accuracy on real migration patterns from your stack. A small model may generate fluent SQL while missing framework transaction rules or compatibility code.

Devin fits work that can be described as a bounded delivery: implement additive fields, add dual-read logic, write a resumable backfill, create tests, and prepare a runbook. It should deliver artifacts, not operate the production database. Human separation between author, reviewer, and executor is a feature here.

No tool wins every migration. Use the findaiverse coding tools hub to form a shortlist, then score each candidate on missing consumers, unsafe SQL, test quality, unrelated edits, review time, and honesty when facts are absent.

Software team reviewing AI generated migration code and compatibility tests

Use expand-and-contract instead of one heroic deploy

Parallel change, often called expand-and-contract, keeps old and new behavior compatible through several releases. Martin Fowler’s parallel change explanation captures the core idea: add the new form, move callers, and remove the old form only after it is unused. Database migrations apply the same pattern to fields, tables, indexes, and contracts.

Phase one expands the schema. Add a nullable field, new table, compatible index, or other additive structure. Do not remove what old code needs. Run the exact DDL against realistic data in an isolated copy and inspect lock and duration behavior. If the engine supports an online or concurrent form, verify its restrictions from current vendor docs rather than assuming the option is always safe.

Phase two makes application code tolerant. Readers may prefer the new field and fall back to the old one. Writers may dual-write, or a database-side mechanism may temporarily keep values aligned. Every approach has failure modes. Dual writes can split after partial failure; triggers can hide cost and surprise maintainers. Pick one, test retries, and add a metric for divergence.

Phase three moves existing data. Run a checkpointed backfill under rate control. Observe normal request latency, locks, transaction logs, replicas, and error counts. Validate data with independent queries. A count match is weak if transformed values can be wrong; sample known edge cases and compare business invariants.

Phase four switches reads and writes. Roll out the new path gradually where infrastructure allows. Keep the old representation during a defined observation period. Dashboards should show use of the old path, missing new values, and discrepancies. A release is not ready for contraction because a deploy completed; it is ready when evidence shows old behavior is no longer needed.

Phase five contracts. Remove compatibility code first or mark it for the same release plan, then remove old database structures in a separately reviewed change. Search repositories, query history, dashboards, exports, and support scripts. Announce deprecation to owners. Destructive cleanup deserves its own rollback or forward-fix plan because restoring dropped data is very different from reverting an application commit.

Design backfills as resumable production jobs

A backfill should behave like a small service. It needs identity, progress, rate limits, error handling, metrics, and an operator. A one-off script with UPDATE ... WHERE new_value IS NULL may be fine for a tiny table, but table size alone does not decide safety. Write rate, indexes, row width, replication, and long transactions all matter.

Choose a stable batching key. Primary-key ranges often work, but gaps and random identifiers can make range sizes uneven. Time windows may fit append-only data, yet late arrivals need another pass. Keyset pagination is usually safer than large offsets because its cost does not grow with progress. Record the last completed boundary in durable state rather than relying on terminal history.

Make each batch idempotent. If the job dies after the database commits but before the checkpoint updates, the same batch will run again. The operation must produce the same result or detect that work is complete. Avoid side effects such as duplicate events or emails. If side effects are required, give them independent idempotency keys.

Rate control should respond to the system, not just sleep for a fixed number of seconds. Set a maximum batch size and concurrency, then watch database latency, lock waits, replica delay, CPU, I/O, transaction-log growth, and application errors. Slow or pause when thresholds cross. The operator needs one obvious stop command and confirmation that no hidden worker continues.

Progress reporting must be honest. “Rows processed” can double-count retries. Report a high-water mark, remaining estimate based on fresh counts, successful batches, retries, failures by reason, and throughput over time. Estimates should carry uncertainty because live data keeps changing. Never let an agent state a production completion time from a laptop benchmark alone.

Validate during and after the run. Compare old and new values using business rules, not only null counts. For a money conversion, check totals and rounding groups. For an identifier change, verify uniqueness and references. For a status mapping, count every source and destination state, including unknowns. Store queries in the runbook so another person can repeat them.

Test compatibility, not merely the final schema

The final schema is only one state in a migration. Build a version matrix. At minimum, test old app with old schema, new app with expanded schema, old app with expanded schema during overlap, and new app after backfill. If rollback may put old code against new data, test that state too. Invalid combinations should be named so release tooling can prevent them.

Start from a realistic prior schema. Creating a fresh database from the latest definitions does not test upgrades. Keep sanitized fixtures or generated datasets for supported prior versions. Apply every migration in order, start the relevant app version, and run contract checks. Then test a fresh install separately; both paths matter.

Test interruption. Kill the backfill midway, restart it, and confirm that progress resumes without duplicate side effects. Inject a malformed row, deadlock, timeout, and lost connection. Verify whether the job retries, quarantines, pauses, or exits according to policy. “Retry forever” is not an error strategy.

Check lock behavior with concurrent traffic in a disposable environment. Hold a representative transaction open, attempt the DDL, and confirm the configured lock timeout or failure behavior. Run ordinary reads and writes while batches execute. The test environment cannot reproduce production perfectly, but it can catch statements that obviously wait or block.

Use query plans for backfill and validation queries. Confirm that the batch predicate uses the intended index and does not drift into full scans as data changes. Plans from staging are evidence, not guarantees; production statistics may differ. The release owner should know how to inspect the current plan without exposing sensitive query results to an external tool.

Finally, test the cleanup later. Removing a field should fail a compatibility test until all old readers and writers are gone. A deprecation metric can prove that old code paths receive no traffic for an agreed period. Cleanup tests protect against impatience—the quiet week after a successful backfill is when teams are most tempted to drop too soon.

Operations team monitoring a controlled database backfill with stop conditions

Review AI migration pull requests by failure mode

Read the pull request in rollout order, not file order. First inspect the change packet and compatibility sequence. Next inspect additive schema changes. Then review application reads and writes, backfill behavior, metrics, tests, runbook, and cleanup plan. Generated files come after their source. This order makes it easier to ask whether each phase can exist safely on its own.

For DDL, identify expected lock level, possible rewrite, transaction behavior, failure duration, disk impact, and replica effect. Require links to the current engine documentation for unusual operations. If the author cannot answer one item, the pull request can remain open while the team measures it. Guessing faster is not progress.

For application code, look for partial failures and retries. Can one side of a dual write succeed? Does a retry create a duplicate? Does fallback logic hide corrupted new data by quietly reading old data? Are cache keys or event schemas affected? Does an older worker overwrite a newer value? AI often writes the happy sequence; reviewers should attack the gaps between steps.

For backfills, inspect the stable key, checkpoint transaction, idempotency, query plan, batch cap, concurrency, pause switch, retry limit, poisoned-row policy, metrics, and final validation. Confirm that ordinary app traffic has priority. A backfill that finishes fastest is not necessarily the one that should run.

For tests, ask whether the old implementation fails where expected, whether mixed-version states run, and whether fixtures represent real edge types without carrying customer data. Check that tests do not mock away the database behavior under review. If the risk is lock timing or transaction isolation, a pure unit test cannot prove it.

Keep the diff single-purpose. A migration is not a good place to upgrade the ORM, rename repository classes, reformat models, and replace test helpers. Those changes can be useful, but mixing them hides cause and makes rollback harder. Give the agent a file and intent budget, then stop for a scope decision when it grows.

Create a release runbook with stop conditions

The runbook names people before commands. List the release owner, database owner, application owner, observer, incident lead, and communication channel. One person may hold several roles on a small team, but the responsibilities should still be explicit. State who can start, pause, resume, and cancel each phase.

Write prechecks with expected results: backup or recovery status, storage headroom, replica health, current deployment version, active long transactions, error baseline, relevant dashboard links, and confirmed maintenance restrictions. Commands should be copied from approved operations docs and reviewed. Do not ask an agent to compose a production shell command during the release call.

For each phase, record the action, expected duration range, observation window, success signal, stop threshold, and rollback or forward-fix action. If a schema change cannot be rolled back safely, say so before execution. “Revert if needed” is not a plan when data has already changed.

Communications belong in the runbook. Product support may need to know about temporary behavior, analytics may need a field transition date, and on-call responders need the change identifier. A short timeline prevents an unrelated alert from being misread and helps the team reconstruct what happened later.

Close only after validation and ownership transfer. Save actual timings, observed lock waits, batch rate, exceptions, final counts, and follow-up cleanup date. Turn surprises into repository rules or test fixtures. The best migration history reduces uncertainty for the next change instead of leaving a successful but unexplained command in chat.

Field notes from findaiverse curation

While curating AI coding products, we find that migration demos reward the wrong moment. Generating a model, migration file, and test looks impressive because the visible diff appears quickly. The hard work sits before and after that diff: discovering consumers, measuring the live table, designing overlap, proving restart behavior, setting release thresholds, and waiting long enough before cleanup.

Our preferred evaluation packet uses a disposable repository and database with one large-enough synthetic table, an old worker, a new API, a replica-lag signal, a poisoned row, and a forbidden production credential file. The agent receives incomplete facts on purpose. We score whether it asks for the engine version, finds mixed readers, chooses an additive phase, produces a bounded backfill, stops at the forbidden path, and reports what the sandbox cannot prove.

We also compare recovery. We interrupt the backfill after a committed batch, rerun it, and inspect counts. We make one validation query slow. We remove a consumer from the repository map but leave a contract fixture. A useful setup leaves a clear checkpoint and exposes uncertainty. A weak one celebrates a green migration command and assumes the rest.

Disclosure: findaiverse lists free and paid AI products. This article is editorial process guidance, not a sponsored ranking or a substitute for your database vendor, SRE, security, compliance, or legal review. Features, model access, pricing, and data terms change. Confirm current vendor documents and test with non-sensitive fixtures before granting an assistant access to a private repository.

Frequently asked questions

What is an AI-assisted database migration?

An AI-assisted database migration is a schema or data change in which a coding assistant helps inspect repository context, draft migration and compatibility code, create backfill logic, generate tests, or prepare documentation. The database owner still supplies production facts, reviews engine behavior, approves the rollout, controls credentials, and decides whether production execution proceeds.

Can an AI coding agent run a production migration?

It may be technically possible, but it is a poor default. Keep production credentials and network access outside the coding-agent environment. Let the agent deliver reviewed code, tests, plans, and a runbook. A named human operator should execute approved commands through the company’s normal change and access controls.

Which agent is best for database migrations?

Cursor suits close, editor-led work; Copilot fits GitHub and existing IDE processes; Windsurf handles longer sandbox loops; Continue offers model and configuration choice; Devin can prepare a bounded ticket in a persistent environment. Your engine, framework, controls, and review cost should decide. Test all candidates on the same migration fixture.

Should every migration use expand-and-contract?

No. A small private table with a coordinated outage may not need a long overlap. Expand-and-contract is valuable when old and new code coexist, traffic cannot stop, rollback matters, or data moves gradually. Write down why a simpler path is safe rather than applying either approach by habit.

How do we verify a generated backfill?

Run it on a disposable realistic dataset, inspect its query plan, interrupt and resume it, retry committed batches, inject malformed rows, measure locks and load, and compare old and new values with business invariants. In production, start slowly, watch agreed metrics, preserve checkpoints, and stop when a threshold is crossed.

Make the migration boring before you make it fast

The best database migration is not the cleverest SQL an agent can produce. It is a sequence whose states are compatible, observable, stoppable, and owned. Build the change packet, expand before moving data, treat the backfill as an operated job, test mixed versions, and delay destructive cleanup until runtime evidence supports it.

Compare Cursor, GitHub Copilot, Continue, and other assistants in the findaiverse coding category, or browse the full AI tools directory. Give each candidate the same fixture—and favor the one that surfaces missing facts over the one that writes the most SQL.

Related Posts