The strangler fig pattern is named after the vine that grows around a host tree, gradually taking over its structural role until the original tree can be removed and the vine stands on its own. Applied to APIs, it means routing traffic to a new implementation incrementally — endpoint by endpoint, or route by route — behind a facade, rather than attempting a big-bang cutover. It's the pattern of choice for migrating a legacy API without a multi-month freeze on new features.
The facade is the whole pattern
The mechanism is a routing facade — usually the API gateway itself — that sits in front of both the legacy system and the new one, and decides per-request which backend handles it. Clients keep calling the same base URL throughout the migration; they have no visibility into which system actually served the request. This is what makes the pattern low-risk compared to a rewrite-and-cutover: at every point in the migration, the system is in a valid, fully-functioning state, just with an evolving split of traffic between old and new.
routes:
- path: /api/v1/invoices/*
upstream: legacy-monolith # not yet migrated
- path: /api/v1/customers/*
upstream: customers-service # migrated, new implementation
- path: /api/v1/orders/*
upstream: orders-service
canary:
legacy-monolith: 90% # in-flight migration
orders-service: 10%
Picking the first slice to migrate
The migration order matters more than the migration mechanics. Start with a route that's low-risk but real — enough traffic to prove the new implementation under genuine load, but not the endpoint that processes payments. A common mistake is migrating the easiest code first regardless of risk profile, which proves the pattern works but doesn't retire any of the complexity that made the legacy system painful in the first place. The better heuristic: migrate the pieces that are both frequently changed and well-isolated, since those are where the legacy system is costing you the most in velocity.
Order the migration by which parts of the legacy system generate the most change requests and bug reports, not by which are easiest to extract. The whole point is to stop paying the legacy tax on the code that hurts most, as early as possible.
Dual writes and the data consistency problem
The part of a strangler migration that goes wrong most often isn't the routing — it's data. If the new service needs its own data store, you either dual-write to both systems during the transition (with all the consistency risk that implies if one write succeeds and the other fails) or have the new service read from the legacy database until its own store is proven out. Dual writes need a reconciliation job checking the two stores agree, because "eventually consistent, we hope" is not a real consistency guarantee — it's an unmonitored assumption.
Cutting the legacy write path the moment the new service looks like it's working removes your fallback and your ability to detect silent divergence. Keep both paths live and monitored until the discrepancy count has been zero for at least one full business cycle.
Knowing when to stop, and actually decommissioning
The strangler pattern has a natural endpoint — the day traffic to the legacy system hits zero — but teams routinely stop short of it, leaving the legacy system running "just in case" indefinitely. That's not a completed migration, it's two systems in permanent parallel, doubling your operational surface. Set an explicit decommission date tied to a traffic threshold (e.g., zero requests for 30 consecutive days) and treat removing the legacy code path as part of the migration's definition of done, not an optional cleanup task for later.
| Phase | Risk | What to watch |
|---|---|---|
| First slice migrated | Low, if chosen well | New service under real load |
| Dual writes active | Highest — data can diverge silently | Reconciliation job results |
| Traffic fully cut over | Low | Legacy system truly idle, not just quiet |
| Legacy decommissioned | None, if done last | Nothing — this is the finish line |
Wrapping up
The strangler pattern trades migration speed for migration safety — every stage leaves you with a working system, which is exactly why it's the default choice over a rewrite for anything customers depend on. The discipline it demands is in the data layer and in actually finishing: reconcile before you cut over, and decommission the legacy path on purpose rather than letting it linger.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.