Legacy Modernization with AI: The Strangler Fig Pattern
Big-bang rewrites fail far more often than they succeed. The strangler fig pattern — incrementally routing traffic away from legacy code until it can be retired — is safer, and AI removes most of its planning overhead.
"Let's rewrite it properly" is the most expensive sentence in software engineering. Full rewrites take longer than estimated, the old system still needs maintenance while the new one is built, and by the time the rewrite ships, requirements have moved. The strangler fig pattern — named after the vine that grows around a host tree until the tree can be removed — replaces the all-or-nothing rewrite with incremental, continuously-shippable migration.
How it works
- Put a routing layer (a reverse proxy, an API gateway, or a facade) in front of the legacy system.
- Build one new module against the new architecture, functionally equivalent to a slice of the legacy system.
- Route traffic for that slice to the new module; everything else still goes to legacy.
- Verify in production with real traffic before routing the next slice.
- Repeat, module by module, until nothing is left routing to legacy — then retire it.
At every point in the process, the system is fully functional and in production. There is no "big cutover night." A bad module can be rolled back by routing traffic back to legacy — a full rewrite has no equivalent rollback.
Where AI actually helps
The planning work — deciding what to extract first, in what order, and how risky each slice is — is normally the slowest part, because it requires understanding a legacy codebase nobody fully remembers writing. This is exactly the kind of large-context analysis AI is strong at, provided you give it the discipline of a structured prompt rather than "look at this codebase and tell me what to do."
Step 1 — migration readiness assessment
Before picking a first module, get an honest picture of what you're dealing with: coupling between modules, test coverage per area, and which parts are actually safe to touch. Feeding a codebase overview to Claude with an explicit rubric produces a more consistent assessment than an ad-hoc "what do you think" — and one you can defend to stakeholders.
Step 2 — module extraction plan
Context: Legacy monolith, .NET Framework 4.8. Here is a module dependency map (which modules call which) and test coverage per module: [paste data].
Task: Rank the top 5 candidate modules for strangler-fig extraction, ordered by what to extract first.
Constraints:
- Score each candidate on: (a) how isolated it is from other modules (fewer inbound dependencies = safer first extraction), (b) test coverage (higher = safer), (c) business value of modernizing it soon.
- For each candidate, state the specific risk of extracting it first, not just the score.
- Do not recommend extracting the module with the most inbound dependencies first, regardless of its business value — that's a routing-layer/big-bang risk in disguise.
Output format: A table with columns: Module | Isolation score | Coverage | Business value | Recommended order | Key risk.Step 3 — the routing layer
A reverse-proxy or API gateway (YARP is a common .NET choice) sits in front of both systems and routes by path, header, or feature flag. This is also where canary rollout and instant rollback live — route 5% of traffic to the new module, watch error rates, then ramp up or roll back.
Common failure modes of the pattern itself
| Failure mode | Cause | Fix |
|---|---|---|
| Extraction never finishes | No forcing function to retire legacy modules once replaced | Set an explicit deadline per extracted module to remove the legacy code path, not just stop routing to it |
| Data drift between old and new systems | Both systems write to separate data stores during transition | Route writes through a single system (usually legacy) during transition, or use a synchronization/outbox pattern |
| "Strangler fig" in name only — actually a parallel rewrite | New system built in isolation, then swapped wholesale | Each extracted module must go live and serve real traffic before the next one starts — that's what makes it incremental |
| Routing layer becomes a second legacy system | Routing logic grows ad hoc without its own tests/ownership | Treat the routing layer as a first-class piece of infrastructure with its own test suite from day one |
The pattern isn't free — it takes longer calendar time than a rewrite would take if the rewrite went perfectly. Its value is that it doesn't require the rewrite to go perfectly; each slice is independently low-risk, verifiable in production, and reversible. The Existing Project Advanced program covers the full assessment-to-extraction workflow, including how to combine this with the .NET Framework → .NET 8 migration path when that's the specific modernization target.