[AI, Software Architecture]

28 Sep 2026

-

9 min read time

AI-Assisted Legacy Modernization Without Breaking Your App

Plan an AI-assisted legacy migration with a focused pilot, acceptance tests, data compatibility and rollback checks before expanding to the rest of your app.

Kalle Bertell

By Kalle Bertell

Violet hands move a mint block between two structures, with green checkpoints marking an incremental software migration.

A migration can compile, pass its new tests and still break the workflow that pays your bills. Perhaps an invoice export now rounds amounts differently. Perhaps a saved link no longer opens the right account. The replacement looks reasonable because nobody wrote down the awkward behavior people depended on.

AI coding agents make it easier to produce a replacement implementation. They also make it easier to produce a large amount of plausible code before anyone discovers that the specification was incomplete. A useful migration process needs a way to establish expected behavior, limit each change and reject incorrect results.

Our recommendation is to start with one business capability, give it an independently reviewed acceptance contract and move it through a repeatable verification process. Expand the migration only when the pilot demonstrates that the team can maintain that process at a reasonable cost.

Decide what the migration must improve

“Move to React” describes a technology change. It does not explain why the business should fund it. A useful objective might be reducing the time needed to add a new checkout step, replacing an unsupported dependency or allowing separate teams to release independently.

Choose a baseline before generating code. Record how long a representative change takes, which incidents recur and which constraints prevent product work. If the team cannot identify a practical improvement, a smaller refactor may be sufficient.

This distinction matters because agents can make a rewrite appear inexpensive during its first week. The unfinished work arrives later: account permissions, exports, translations, analytics, background jobs and the release process. An estimate that covers only visible screens leaves much of the system unpriced.

For an Angular-to-React project, for example, the first question is whether the current application can support an independently mounted feature with a stable API. Our guide to Angular-to-React migration strategies covers that framework transition. The process below addresses how to use agents while preserving the product contract.

Choose a feature that exposes real constraints

A static settings page proves very little. Choose something small enough to finish but substantial enough to exercise the architecture: an order search, an account editor or a report with permissions and export behavior.

Consider an illustrative order-management migration. The pilot lets a support agent find orders, filter by status and download the results. It touches routing, authentication, query parameters, a backend endpoint, a table and a file download. It also offers a clear boundary: the existing application can continue to handle everything else.

Write a short description of that boundary. Name the routes, inputs, outputs, data owners and excluded behavior. Decide whether the new feature reads through an existing API or requires an adapter. Identify any shared session state that could make rollback difficult.

Martin Fowler’s Strangler Fig approach describes replacing a system gradually while old and new implementations coexist. Agents can help build the replacement pieces. Engineers still have to choose the boundaries and account for the temporary integration work.

Capture behavior before asking for a replacement

An agent can inspect handlers, follow imports and suggest edge cases. Treat those findings as an inventory for review. The existing code may contain accidental behavior, dead branches or workarounds that should disappear.

Give each discovered behavior one of three decisions: preserve it, change it deliberately or investigate it. Ask the person who owns the workflow to resolve ambiguous cases. A support team may depend on a surprising export order; a developer reading the code alone cannot know that.

For the order-search example, a first acceptance contract could look like this:

Scenario

Required result

Evidence

Open a saved filtered URL

Restore the filter and display matching orders

Browser test against a known fixture

Request another tenant’s order

Deny access without exposing its details

API authorization test

Search returns no matches

Show an empty state and retain the search

Browser interaction test

Export filtered results

Use the agreed columns, values and ordering

Parsed file comparison

Request times out

Show a retry action without clearing the filter

Controlled failure test

Use only the keyboard

Reach filters, results and export controls

Keyboard walkthrough

Keep this contract outside the agent’s implementation patch. A failing requirement should not disappear because the agent edited the assertion until the build turned green.

Existing behavior tests are useful even when they expose defects. Record the defect separately and decide whether fixing it belongs in this migration. Combining a rewrite with untracked product changes makes discrepancies much harder to interpret.

Give the agent a bounded task

An effective task includes the target behavior, the relevant source files, the architecture it must follow and the checks that define completion. Include one approved example of a neighboring feature where possible. That is usually more useful than a long collection of general coding preferences.

For our sample feature, the first task might be: implement the filter controls and URL synchronization using a fixed dataset. Exclude network requests and export. Require that changing a filter updates the URL and that reloading the URL restores the same selection.

The next task introduces the existing API, loading states and request cancellation. Export follows only after filtering behaves correctly. This sequence makes it possible to inspect a meaningful result at each stage.

Keep credentials and production writes outside the task’s working environment. Give the agent synthetic data and a disposable environment. When a task needs a service integration, provide only the capability required for the test. This keeps the migration reproducible and reduces the number of unrelated systems that can affect a result.

Shopify’s Helix migration tooling offers a useful example of enforced checkpoints. Its process combines behavioral validation, visual inspection, code review and engineer approval. The transferable idea is a stop condition that the implementation cannot override. The exact tooling will depend on your application.

Separate the checks that catch different failures

A migration needs several kinds of evidence because each catches a different class of mistake. Passing a unit test says little about whether a deep link survives. A screenshot says little about whether the server checks tenant access.

Start with fast checks for the changed logic and API contract. Then exercise complete user workflows through the browser. Finally, review the implementation for maintainability and inspect the actual interface.

Where both versions can run against the same synthetic inputs, compare their outputs. Normalize only fields whose differences are understood, such as generated timestamps. Do not remove every mismatching field simply to obtain equality. A difference in tax rounding or pagination may be the regression you need to catch.

Visual comparisons work best with a fixed browser, viewport, font setup and dataset. Playwright’s screenshot assertions support that workflow, but rendering differences between environments can produce noise. Keep reference generation and verification consistent. Review an intentional visual change rather than automatically accepting a new baseline.

For behavior that involves external side effects, use test doubles or a dedicated integration environment. Replaying an order-submission flow against production would create new orders; mirroring a read-only search does not carry the same consequence.

Give the human reviewer a compact package: the acceptance contract, the changed behavior, test results, representative screenshots and unresolved decisions. A large generated explanation is not a substitute for evidence they can inspect.

Treat data compatibility as a separate workstream

A frontend rollback is straightforward only if the old application can still understand the data. If the new version writes a different status value, removes a field or changes the meaning of a timestamp, switching routes back may leave the old system unable to operate.

Prefer a staged data transition. First add a representation that both versions can tolerate. Move readers and writers deliberately, verify the transition, and remove the old representation after the rollback window closes. The exact sequence depends on who owns the data and how many consumers exist.

Avoid casual dual writes. If two stores receive an update and one write fails, you now need reconciliation rules. For the order-search pilot, keeping writes in the existing backend may be the simplest way to contain that problem.

Document which version is authoritative at every stage. Include background workers, integrations and scheduled exports in that map. They are easy to miss when the migration begins with a browser screen.

Release to a small audience with an executable rollback

A feature flag is useful when it selects a complete, understood path through the system. Test both positions of the flag before release. Make sure changing it does not strand a user halfway through a workflow or split a transaction between incompatible implementations.

Start with an internal cohort or a small customer group suited to the feature. Define the signals that would stop expansion: error rates, failed exports, support reports or an unacceptable change in response time. Assign a person who can make that decision.

The rollback instructions should describe a procedure another engineer can execute. Record the switch to change, the data compatibility assumptions, the checks to run afterward and any work that cannot be reversed automatically. Rehearse the procedure in staging.

Analytics deserves its own check. Preserve event names and meanings where continuity matters, and distinguish old and new implementations when comparing them. Otherwise a tracking change can look like a product improvement. Our article on preserving analytics during a website migration covers that concern in more detail.

Measure accepted work, including the cost of review

Count the time needed to deliver an accepted feature. Include investigation, preparation, agent execution, human review, rework, integration and release support. Record model and infrastructure costs too, but avoid letting a small compute bill obscure a large review burden.

Useful pilot measures include the number of failed acceptance checks, defects found after release, time spent reconstructing missing requirements and the ease of making a follow-up change. Generated lines of code do not tell you whether the migration became cheaper to own.

Compare the pilot with a credible alternative: improving the same feature in the existing system. If most effort went into a backend contract shared by both approaches, attributing the whole improvement to the rewrite would be misleading.

Before expanding, ask whether another engineer can repeat the process using the documented checks. A successful pilot that depends on one person remembering every exception will be difficult to scale.

When to pause the migration

Pause when nobody can resolve important behavior questions, the data cannot support a reversible release, or test failures repeatedly reveal that the boundary is larger than expected. Those findings justify more discovery or a smaller scope.

Also pause when the first feature is easy to generate but hard to change afterward. Ask the agent to implement one realistic follow-up requirement, then review the result. That exposes abstractions and duplication that a one-shot demonstration can hide.

A productive next step is a migration assessment with one representative feature, a compatibility plan and explicit acceptance criteria. Makers’ Den’s software modernization service can help establish those boundaries and carry the work through implementation. The decision to expand should follow evidence from the pilot.

Kalle Bertell

By Kalle Bertell

More from our Blog

Keep reading