You can replace a legacy system while it is still serving live traffic. The pattern for doing it is called the strangler fig, and it works by routing one slice of functionality at a time away from the old system and into a new one, until the old system is handling nothing and can be switched off. Nobody stops work, and no single weekend decides whether the business survives.
The name comes from the strangler fig tree, which grows around a host tree and gradually takes over its structure. Martin Fowler applied it to software in 2004, and it has since become the default approach for high-risk replacements in banking, insurance and logistics. What follows is how it actually runs in practice, including the parts that are harder than the diagrams suggest.
Key Takeaways
- A strangler fig migration routes traffic slice by slice from the legacy system to its replacement, so there is never a single cutover event.
- The routing layer, usually an API gateway or facade, is the piece that makes the pattern work and the piece most teams underinvest in.
- Dual-write and reconciliation are the hard part, not the new code. Plan for data drift between the two systems from day one.
- Pick the first slice for low blast radius and clear boundaries, not for business importance.
- The migration is only finished when the legacy system is switched off. Half-migrated systems cost more to run than either end state.
Why big-bang replacement keeps failing
A big-bang replacement builds the new system in full, then swaps it in on a chosen date. It appeals to steering committees because it produces one date and one number. It fails because every assumption made in month two is only tested in month eighteen, when the cost of being wrong is at its highest.
Three things go wrong reliably. The legacy system keeps changing during the build, so the target moves. Undocumented behaviour surfaces only under production load, long after the new system was declared feature complete. And the rollback plan, which looked fine on paper, turns out to be unusable once real customer data has been written into the new system for six hours.
Our pillar article on legacy system modernization without the big-bang risk covers the strategic case for progressive delivery. This piece is about the mechanics.
How the pattern works
Strangler fig pattern: an incremental replacement approach where a routing layer sits in front of a legacy system and progressively redirects individual capabilities to a new implementation, until no traffic reaches the original.
Three components make it work. First, a facade or routing layer that every caller goes through, so you control where any given request lands. Second, the new implementation of one capability at a time. Third, a data strategy that keeps both systems consistent for as long as both are live.
The facade is the load-bearing piece. It can be an API gateway, a reverse proxy with routing rules, an application-level adapter, or in some ERP contexts an integration layer that fronts the existing modules. What matters is that switching a route is a configuration change rather than a deployment, because that is what turns a rollback into a thirty-second operation instead of an incident.
Teams frequently try to skip the facade and have callers point directly at whichever system owns a capability. That works until you need to roll back, at which point you are redeploying every consumer under pressure. Build the facade first, even when the first slice is small enough that it feels unnecessary.
Choosing the first slice
The instinct is to start with the most valuable capability. That is usually wrong. The first slice exists to prove the routing, the deployment path, the monitoring and the rollback, so it should be chosen for low blast radius and clean boundaries.
Good first candidates read more than they write, have few dependencies on other modules, and have a clear owner who can define correct behaviour. Reporting and lookup endpoints often fit. Reference data services fit. Anything that touches the money movement path on day one does not.
Once the first slice has been in production for a few weeks without incident, the team has something more useful than a delivered feature. It has a repeatable migration route, and every slice after that is a known quantity.
The data problem, which is the real problem
While both systems are live, both need correct data. There are three workable approaches, and the choice constrains everything else.
Keeping the legacy database as the single source of truth and having the new service read and write to it is the simplest option, and it lets you migrate behaviour without migrating storage. The cost is that the new system inherits the old schema, which is often the thing you were trying to escape.
Dual-writing to both stores gives the new system a clean schema immediately, but it introduces a distributed consistency problem. Writes can succeed in one store and fail in the other. This needs an outbox pattern or a change data capture stream rather than two direct writes in application code, and it needs reconciliation.
Change data capture (CDC): reading a database’s transaction log to stream every committed change to another system, so a second store stays current without the application writing to it twice.
Migrating ownership per entity, so each table or aggregate has exactly one authoritative system at any time, is the cleanest of the three but requires the sharpest domain boundaries. It works well when the legacy system is genuinely modular and poorly when everything joins to everything.
Whichever you choose, build the reconciliation job before you build the second slice. It should compare both stores on a schedule and alert on divergence. Teams that add reconciliation later invariably discover that the systems have been quietly disagreeing for weeks. Our note on legacy data migration goes deeper on reconciliation and cutover mechanics.
Running it without stalling
The most common failure of a strangler fig migration is not a technical one. It is stopping halfway. The first three slices deliver visible progress, attention moves elsewhere, and the organisation settles into running two systems permanently. That is the most expensive possible outcome, because it carries the cost of both platforms plus the integration between them.
Two things prevent it. First, track the percentage of traffic still served by the legacy system as a headline metric, reported alongside delivery numbers. It makes stalling visible to people who can do something about it. Second, agree the decommissioning date and the criteria for it at the start, and treat switching off the old system as a deliverable rather than a cleanup task.
Expect the last ten percent to be disproportionately hard. It is where the batch jobs, the regulatory reports, the one integration nobody documented and the process that runs annually all live. Budget for it explicitly instead of discovering it.
Where this fits alongside packaged software
The pattern is not limited to custom builds. When the replacement is a packaged platform, the same routing discipline applies: bring modules across progressively, keep the facade in front, and reconcile between the two. Most of the risk in an ERP programme comes from the same place as a custom rebuild, which is the assumption that everything moves at once. Our ERP implementation practice runs phased cutovers for exactly this reason.
Frequently asked questions
How long does a strangler fig migration take?
Longer end to end than a big-bang plan claims to take, and shorter than a big-bang plan actually takes. A mid-sized core system usually runs twelve to twenty-four months, with the first slice in production inside eight to twelve weeks. The difference is that value arrives throughout rather than at the end, and the programme can be paused without leaving the business stranded.
Is it more expensive than a full rewrite?
The direct engineering cost is somewhat higher, because you build routing, run two systems in parallel and pay for reconciliation. The total cost is usually lower, because the failure modes that make rewrites expensive, being wrong about requirements and finding out late, are caught within weeks instead of quarters.
What if the legacy system has no clear module boundaries?
Then the first work is finding seams rather than writing new code. Usually that means identifying entry points, such as screens, endpoints or batch jobs, and treating those as the unit of migration rather than internal components. It is slower to start, but a monolith with no internal structure is precisely the case where a big-bang rewrite is most likely to fail.
Do we need microservices to do this?
No. The replacement can be a single well-structured application. The pattern is about how you route and cut over, not about how the new system is decomposed. Adding a distributed architecture to a migration that did not need one is a common way to double the difficulty.
Can this work while the legacy system is still receiving changes?
Yes, and it has to, because the business will not stop. The rule that keeps it manageable is that once a capability has been migrated, changes to it happen only in the new system. Without that rule you end up maintaining both implementations of the same logic, which is worse than either system alone.
Planning a legacy replacement?
Kentro runs progressive modernization programmes for banks, insurers and enterprises across the UAE and GCC, including the routing, data and reconciliation work that decides whether they finish.

