Migrate a codebase with an agent.

Framework upgrades, library swaps and language ports. What the published case studies did, with their real numbers, and a codemod you can run.

Stacked moving boxes in an empty apartment
Photo by Alicia Christin Gerald on Unsplashdithered by Cyborb

To migrate code with AI, split the work in two. Codemods, small programs that rewrite code by its structure, handle the mechanical changes. An agent handles the cases that need judgment. Your test suite decides when each batch is done.

Inventory first, migrate in small batches, and keep the old and new versions side by side until their results match. That is also what the teams behind the best published case studies did.

The short version
  • Start with an inventory: every file and API the migration touches, counted, so you can track progress.
  • Use codemods for one-to-one changes and an agent for anything where the meaning changes.
  • Migrate in small batches, and let each batch go green in CI before the next one starts.
  • For rewrites and ports, run old and new side by side and compare outputs before you switch.
  • Published results are strong but not magic: Airbnb automated 97% of its files, Slack converted 80% of the code in a nine-file sample, and people finished the rest.

Migrating code with AI: what the case studies show

The best evidence comes from teams that wrote up real migrations with real numbers.

6 weeks
for Airbnb’s test migration, estimated at 1.5 years by hand
Airbnb Engineering, 2025
80%
of the code converted correctly at Slack by a codemod and an LLM together, in a nine-file sample
Slack Engineering, 2024
50%
less total time on Google’s migrations, by its developers’ estimate
Google, 2025
TeamMigrationApproachResult
AirbnbAbout 3,500 React test files, Enzyme to React Testing LibraryLLM pipeline with per-file steps, retry loops and prompts of 40,000 to 100,000 tokens75% of files in 4 hours, 97% after 4 days of tuning, the rest by hand
SlackMore than 15,000 Enzyme tests, same moveSyntax-tree codemod plus Claude 2.1, fed the rendered page structureCodemod alone 45%, LLM alone 40 to 60%, both together 80% on nine evaluated files. In a wider run, about 500 of 2,300 test cases passed
Google39 internal migrations over 12 monthsTools find where to change, an LLM writes the edits, developers review74% of submitted code changes generated by the LLM
Stripe3.7 million lines, Flow to TypeScriptCustom codemod, no LLMOne pull request, with 37,000 type errors suppressed by comments

The pattern repeats. Nobody pointed an agent at a repository and said “migrate”. Each team broke the work into small units, automated the repetitive part and checked every result with tests or reviewers.

Step 1: plan and inventory the migration

Start with the official migration guide, not the model’s memory. A model trained before the new version shipped will confidently use old APIs. Our prompts for coding agents include a batch migration prompt that makes the agent read the guide first.

Then count the work. A one-line search gives you a burndown number you can track daily. Here it is on a small test suite moving from Jest to Vitest:

Terminal
grep -rhoE "jest\.[a-zA-Z]+" src | sort | uniq -c
Text
   4 jest.fn
   2 jest.mock
   1 jest.requireActual
   1 jest.spyOn

Sort every item into one of three groups:

  • Mechanical. A pure rename, where old and new behave the same. Codemod territory.

  • Patterned. The same shape with a few variants. A codemod plus review, or an agent with examples.

  • Judgment. The meaning changes, so someone has to think. Agent territory, with close review.

Finally, pick a pilot: three to five files of mixed difficulty. They will expose surprises before you touch the other hundred.

Step 2: codemods versus agents

CodemodAgentBoth together
Best atRepetitive one-to-one changesChanges that need context and judgmentLarge migrations with a long tail
Same input, same outputAlwaysNot guaranteedFor the mechanical part
At 10,000 call sitesSecondsSlow, and costs tokensCodemod for bulk, agent for leftovers
Typical failureMisses unusual shapesInvents APIs or edits testsFewer failures, because each covers the other

Here is the mechanical part of the Jest to Vitest move as an ast-grep rule. It rewrites jest.fn and jest.spyOn, which have direct equivalents in Vitest, and nothing else:

jest-to-vitest.yml
id: jest-fn-and-spyon
language: TypeScript
rule:
  pattern: jest.$METHOD($$$ARGS)
constraints:
  METHOD:
    regex: ^(fn|spyOn)$
fix: vi.$METHOD($$$ARGS)

Install it first with npm install --save-dev @ast-grep/cli. The CLI’s npm package is @ast-grep/cli, not ast-grep. This is the real output with ast-grep 0.45.3, followed by the inventory again:

Text
$ npx ast-grep scan --rule jest-to-vitest.yml --update-all src
Applied 5 changes
$ grep -rhoE "jest\.[a-zA-Z]+" src | sort | uniq -c
   2 jest.mock
   1 jest.requireActual

The leftovers are exactly the judgment calls, and Vitest’s migration guide explains why. In Jest, a mock factory’s return value becomes the module’s default export. In Vitest, the factory must return an object that names each export, so some jest.mock calls convert as they are and others need rewriting. And jest.requireActual becomes await vi.importActual, which is asynchronous, so the code around it changes too. A blind rename would break some of these tests.

The best trick is to let the agent write the codemod. A codemod is short, reviewable and runs the same way every time. A thousand hand edits by an agent are none of those.

PromptWrite a codemod instead of editing by hand
We are migrating [from X to Y]. The official guide is at [URL].
Write a codemod with [ast-grep, jscodeshift or OpenRewrite] for the changes that are one-to-one renames. Do not include anything whose behavior differs.
Run it on [3 pilot files], show me the diff, and run their tests.
Then list every remaining use of the old API, grouped by pattern, with what each one needs.

For Java upgrades, OpenRewrite offers ready-made recipes, such as migrating to Java 21 or 25. For JavaScript and TypeScript, jscodeshift is the long-standing option, and ast-grep works across many languages.

Step 3: migrate in small batches

Before the first batch, make the test suite green and fix any flaky tests. A migration on a red baseline cannot tell you what it broke. If the code has thin tests, write characterization tests first, as described in our guide to refactoring legacy code with AI.

Then repeat a short loop for each batch:

  1. Run the codemod on the batch

    One folder or one pattern at a time. Commit the result on its own, so a reviewer sees mechanical changes separately from judgment calls.

  2. Hand the leftovers to the agent

    Give it the guide, two already-migrated files as examples and the remaining list. Airbnb found that choosing the right related files mattered more than a perfect prompt.

  3. Validate every file, and retry failures

    Run the tests, the type checker and the linter on each file. Feed failures back to the agent for a fixed number of retries, then set the file aside for a person.

  4. Merge only when CI is green

    Keep each batch small enough to review. Update the inventory count, and start the next batch.

Airbnb calls its tuning loop “sample, tune, sweep”: take a sample of failing files, improve the prompt or script, then rerun everything that still fails.

Step 4: run old and new side by side

Upgrades and swaps can usually be proven with the test suite alone. Language ports and rewrites need more, because the new code shares no tests with the old one by default.

  • Dual runs. Send the same inputs to both versions and log every difference. Explain each one before you switch.

  • Feature flags. Route a small share of real traffic to the new version, with a switch to go back instantly.

  • One slice at a time. Replace one route, job or module, confirm it matches, then move on.

This is the strangler fig approach: the new system grows around the old one until the old one can be removed. It keeps every step small enough to undo.

FAQ

Can AI migrate a whole codebase on its own?

Not in any published case we found. The best results came from pipelines that split the work into small units, validated each one automatically and sent the hard remainder to people. Plan for a human-finished tail.

Should I use a codemod or an AI agent?

Both. Use a codemod for changes that are identical everywhere, because it is fast and predictable. Use an agent where the meaning changes. Slack’s numbers show the combination beating either one alone.

How long does a migration with AI take?

It depends on size, test coverage and how much of the change is mechanical. For scale, Airbnb migrated about 3,500 test files in six weeks. Google’s developers estimated they spent half the time of earlier manual migrations.

Which coding agent is best for migrations?

Any capable agent that can run your tests and read files at scale will do. Context size and cost per file matter more than small benchmark gaps. Our comparison of the best AI coding agents covers the options.

Read next: spec-driven development for planning the migration itself, or how to run a coding agent in CI for batch jobs.

Sources
  1. Accelerating large-scale test migration with LLMs, Airbnb Engineering, 2025
  2. Balancing old tricks with new feats: AI-powered conversion from Enzyme to React Testing Library at Slack, Slack Engineering, May 2024
  3. Migrating code at scale with LLMs at Google, Ziftci and others, April 2025
  4. Migrating millions of lines of code to TypeScript, Stripe, 2022
  5. Migrating from Jest, Vitest documentation, accessed September 2026
  6. ast-grep, ast-grep documentation, accessed September 2026
  7. Quick start, ast-grep documentation, accessed September 2026
  8. Migrate to Java 25, OpenRewrite documentation, accessed September 2026
cyborb.ai

Stop reading about it. Build it.

Describe what you want in plain words. Cyborb plans the work, writes and runs the code, makes the assets, and puts the result online.

Download Cyborb

Free to start. No card required.