← All posts ARCHITECTURE

The Strangler Fig Pattern in Practice: A Step-by-Step Legacy Migration Playbook

How to replace a 15-year-old monolith while it keeps taking production traffic — without betting the company on a rewrite.

By Swetha Golla · 6 min read · Senior Application Architect

TL;DR

The Setup

You've inherited a 15-year-old order-management monolith at a fictional logistics firm. It processes 40k orders a day, three of the original engineers are gone, and the test coverage is a rumor. Leadership wants it "modernized" by next year, and the loudest voice in the room is proposing a clean-slate rewrite.

That rewrite will fail. Not because the team is bad — because the legacy system encodes a decade of business rules nobody has written down, and a rewrite forces you to rediscover all of them at once, in production, on launch day. The strangler fig pattern rediscovers them one slice at a time, with a rollback lever in your hand. Here's the playbook.

Martin Fowler named this pattern after watching actual strangler fig vines on a trip to Queensland: the vine germinates in the canopy of a host tree, sends roots down around the trunk, and over years grows into its own self-sustaining structure as the original tree dies inside it. Swap "tree" for "monolith" and you have the whole strategy — the new system grows up around the old one, taking over piece by piece, until one day the host isn't load-bearing anymore. It's not a novel idea I'm pitching here; it's a well-worn technique documented in AWS's and Microsoft's own migration guidance, among others, precisely because it keeps working across very different stacks.

Traffic migration progression: the facade/router shifts traffic from the legacy system to the new system across four snapshots — 0%, 25%, 75%, 100%. Facade / Router (controls the split at every stage) 0% Legacy system — 100% 25% Legacy — 75% New — 25% 75% Legacy — 25% New — 75% 100% New system — 100% Legacy system New system Same facade routes every snapshot — only the dial changes.

The Five-Stage Playbook

Click each stage. Every one of these is a shippable milestone with its own risks — treat them as gates, not a Gantt chart.

Strangler Fig vs. Big-Bang Rewrite

DimensionStrangler FigBig-Bang Rewrite
Risk exposure Bounded per slice — a bad migration affects one route, rolled back in minutes. Total at cutover — every undiscovered business rule fails on the same day.
Time to first value Weeks — first new feature ships on the new stack while the monolith still runs. 12–24 months — nothing ships until everything ships. Scope grows the whole time.
Team disruption Sustained dual-system tax — you run two stacks for the whole migration. But no feature freeze. Feature freeze — the business waits, then demands "just one thing" in the legacy system anyway.
Rollback-ability Built in — the facade is a routing table; flip a percentage back to legacy. Effectively none — rolling back a cutover after data has diverged is a second migration.

RULE OF THUMB

If the legacy system still serves production traffic and you can't recite its business rules from documentation, you don't rewrite it — you strangle it. Big-bang is only for systems small enough to fully re-spec in under a quarter. This isn't a free lunch: you're trading a single catastrophic risk for a longer migration and a facade layer you now have to run — it's a better trade for most legacy systems, not a risk-free one.

The Part Everyone Underestimates

The facade. Teams treat it as an nginx config and a Friday afternoon. It isn't. It owns authentication passthrough and consistent error semantics — production infrastructure with its own SLA.

It also owns translation, and that job has a name: an anti-corruption layer, a pattern Eric Evans defined in Domain-Driven Design for exactly this situation — two systems with incompatible models that still have to talk. Without one, calls pass straight through and the legacy system's quirks — denormalized tables, overloaded status codes, "status=3 has meant something different since 2019" logic — leak directly into your clean new domain model, and months of migration work end up recreating the same debt in new syntax. Worse, that leakage is exactly what makes stage 5 impossible: you can't retire a legacy system your new one has quietly come to depend on.

When the facade is flimsy, every migration slice becomes a firefight. Staff it like a real component: an owner, tests, observability, a one-line rollback path, and explicit translation logic at the boundary — not an assumption that old and new data shapes match. And be honest about the trade you're making — if the migration stalls (and they do stall, when priorities shift), that facade doesn't disappear. It becomes a permanent extra hop and a second system to maintain. A strangler fig that never finishes is just a new kind of legacy. In my experience, migrations that fail outright don't fail on the new services — they fail because the seam between old and new was treated as an afterthought instead of the thing the whole plan hinges on.

See the working example →  A runnable facade-router POC that simulates the 0% → 100% traffic shift, by strangler-fig-migration-playbook on GitHub. Disagree with the playbook? Tell me where — I'd genuinely like to hear which stage broke for you.

SOURCES & FURTHER READING