ArchitectureImplementation
The strangler fig pattern: replacing a legacy system one capability at a time
The strangler fig pattern replaces a legacy system gradually. A routing layer sends each request to either the old or the new implementation, and capabilities move across one at a time until the legacy system has nothing left to do. This page covers where to cut, how to intercept traffic, how to keep legacy semantics out of the new design, how data ownership moves and when another approach fits better.
On this page
- Why incremental replacement usually beats a rewrite
- Reference layers of a strangler fig migration
- Finding seams and sequencing the capabilities
- Choosing the interception layer
- Keeping legacy semantics out with an anti-corruption layer
- Data: change data capture and the dual-write trap
- Transitional architecture and the cost of running two systems
- Decommissioning a strangled legacy system
- When the strangler fig is the wrong choice
- Questions and answers
- Sources
Why incremental replacement usually beats a rewrite
Martin Fowler named the pattern after strangler figs, which grow around a host tree and eventually take its place1. Applied to software, new services grow around the legacy system behind a façade that intercepts requests and routes each one to the old or the new implementation, so callers keep the same interface throughout2.
A full rewrite delivers nothing until the end, has to chase a legacy system that keeps changing, and concentrates all the risk in one cutover. Incremental replacement lets each capability go live, be verified against the old behavior and be switched back if needed. That fits the aim of ColdAI's platform modernization work: moving legacy systems to modern, cloud-native architectures while keeping the business running and preserving critical business logic4. Where the main job is translating old code, such as COBOL, into a modern language, see AI-assisted legacy code modernization instead.
Reference layers of a strangler fig migration
- Clients and channels
Web, mobile, partner APIs and batch senders keep using the same entry points.
- Interception layer
Gateway, reverse proxy or event router that decides where each request goes.
- Routing rules and flags
Per-capability and per-segment rules that can be reversed without a deployment.
- New services
Rebuilt capabilities on the target platform, each with its own data store.
- Anti-corruption layer
Translates between the new domain model and legacy formats in both directions.
- Legacy system
Still serves every capability not yet migrated.
- Change data capture
Streams changes from the owning store so the other stays consistent while ownership moves.
Finding seams and sequencing the capabilities
Map capabilities and the data they own
List business capabilities, such as quoting, billing or customer lookup, with the tables, files and jobs each reads and writes. Seams sit where a capability's data is mostly its own.
Separate read paths from write paths
Reads can usually move first, served from a replicated store, while the legacy system keeps writing. That proves the interception layer and the new platform with little risk.
Pick a valuable, loosely coupled first capability
The first slice should matter to the business but touch few shared tables. A trivial first slice proves nothing; a tightly coupled one stalls the program.
Agree equivalence tests before building
Write down what counts as the same result, including intended differences, so disputes are settled by evidence later.
Run shadow traffic
Copy live requests to the new service, compare its responses with the legacy ones automatically and investigate every difference before any user is routed.
Move users by segment, then move data ownership
Shift a small segment through routing rules, widen it as results hold, then make the new store the owner of that entity.
Choosing the interception layer
| Criterion | API gateway | Reverse proxy | Event interception |
|---|---|---|---|
| Works when | The legacy system already exposes services to its callers. | Callers use HTTP, including screens rendered by the legacy system. | Integration runs through queues, files or database events. |
| Routing granularity | Per operation, with identity and headers available. | Per URL path; finer rules need custom logic. | Per message type or topic, with content-based routing possible. |
| Main trade-off | Becomes critical infrastructure that must not be a single point of failure or a bottleneck2. | Simple to start, but screen-level routing forces whole user journeys to move together. | Ordering, duplicates and replay must be handled explicitly. |
| Switching back | Point a route back at the legacy back end. | Change a path rule. | Repoint the subscription; processed messages may need replay. |
Many migrations use two of these at once, for example a gateway for online traffic and event interception for batch feeds.
Keeping legacy semantics out with an anti-corruption layer
During migration, new services must still call unmigrated legacy functions, and legacy code must call migrated ones. Without a translation boundary, the new design quietly adopts legacy codes, field names and status models. The anti-corruption layer, first described by Eric Evans in Domain-Driven Design, translates between the two models so neither has to understand the other3.
Keep it to translation: business rules placed in the layer become a second legacy system. Version its mappings, log every translation with a correlation identifier, and decide at the outset whether it is temporary or will stay for partners who never migrate3.
Data: change data capture and the dual-write trap
Transitional architecture and the cost of running two systems
The routing layer, the translation layer and the sync jobs are temporary infrastructure with real running costs, so treat them as a liability to retire.
The migration stalls at the transactional core
Early signalRead-only capabilities have moved, but the core write path has no date.
MitigationSchedule one core write path early so the program proves it can move one.
Two systems' costs run for years
Early signalLegacy license and hosting renewals keep being approved for one more term.
MitigationPut decommission dates and contract notice periods on the roadmap and report legacy run cost as a program metric.
Equivalence disputes
Early signalUsers say the new system calculates differently and nobody can show which is right.
MitigationAutomated diffing of shadow traffic against an agreed list of intended differences.
Temporary layers become permanent
Early signalNobody owns removing routing rules and translation code after migration.
MitigationMake removal part of each capability's definition of done.
Decommissioning a strangled legacy system
When the strangler fig is the wrong choice
- If
Requests to the legacy system cannot be intercepted, as with a closed package that has no routable interface.
ThenPlan a package replacement with a rehearsed cutover instead2.
- If
The system is small and well understood.
ThenReplace it in one release.
The routing and translation layers would cost more than they save.
- If
The legacy platform must be exited by a fixed date, such as a data center closure or end of vendor support.
ThenRehost or replatform first to meet the date, then modernize incrementally on the new platform.
- If
The business process itself is being redesigned.
ThenMigrate by business unit or process, not by technical capability.
Reproducing the old behavior faithfully is not the goal.
Questions and answers
How long does a strangler fig migration take?
It depends on the number of capabilities, how tangled their data is and how fast the organization can absorb change. Programs are usually measured in quarters or years rather than weeks, which is why each capability should deliver value and retire legacy cost as it moves, rather than waiting for the end.
Does the strangler fig pattern require microservices?
No. The new side can be a modular application, a SaaS product or a set of services. What the pattern needs is a way to intercept and route requests, clear capability boundaries and a plan for moving data ownership. Microservices are one target architecture, not a precondition.
Can the pattern be used to replace a packaged system such as an ERP?
Partly. Capabilities exposed through APIs or integration layers, such as pricing or customer lookup, can often be peeled away. The tightly integrated transactional core of a package usually cannot be intercepted cleanly, so many programs strangle the edges and then replace the core with a planned cutover.
How is this different from AI-assisted code translation?
Code translation converts existing programs into another language, largely keeping their structure. The strangler fig pattern is an architecture for moving capabilities into a new design while both systems run. They combine well: translated or rebuilt code can be one way to produce the new services behind the routing layer.
Sources
- Strangler Fig — Martin Fowler · checked 10 October 2026
- Strangler Fig pattern — Microsoft Azure Architecture Center · checked 10 October 2026
- Anti-Corruption Layer pattern — Microsoft Azure Architecture Center · checked 10 October 2026
- Implementation: platform modernization offering — ColdAI