Strangler Fig Pattern
Rewriting a large legacy system from scratch is one of the riskiest projects in software. Big-bang rewrites routinely overrun, miss hidden behaviors the old system handled, and deliver nothing until the final cutover, which then fails. The strangler fig pattern, named by Martin Fowler after vines that gradually envelop and replace a host tree, takes the opposite approach: incrementally build new functionality around the old system, route traffic piece by piece to the new implementation, and eventually retire the legacy code.
It's the standard way to decompose a monolith into microservices, migrate to a new platform or framework, or move to the cloud, while continuously delivering value and keeping the ability to roll back each step.
TL;DR
- Put a routing façade (a proxy, API gateway, or router) in front of the legacy system.
- Extract one capability at a time into the new system, and route its traffic there; everything else still goes to legacy.
- Start with slices that are valuable, loosely coupled, and low-risk, and learn from each.
- Protect the new system's model with an anti-corruption layer when it must talk to legacy.
- Migrate data carefully: CDC or sync, dual running, backfills, and a clear system of record per entity.
- Use shadow traffic, canaries, and feature toggles to validate, and delete legacy code as you go.
Quick Example
Routing at the edge while migrating the catalog and search from a monolith:
Over months, more routes move to new services, until the location / fallback handles nothing meaningful and the monolith can be switched off.
Core Concepts
The Routing Façade
The façade intercepts all requests and decides whether legacy or new code handles each one:
- Edge proxy or API gateway: route by path, host, header, or percentage (Nginx, Envoy, cloud load balancers, an API gateway).
- In-application routing: branch by abstraction inside the monolith, calling new services behind interfaces.
- Event interception: for message-driven systems, redirect or duplicate messages to new consumers.
The façade makes each migration step small and reversible: flip a route back if something goes wrong.
Choosing What to Extract First
Good first candidates:
- High value, frequently changing areas, where independent deployment pays off fastest.
- Loosely coupled capabilities with clear boundaries and few shared tables (notifications, search, reporting, product catalog).
- Edge features read-heavy enough to be replicated safely.
Avoid starting with the most entangled core (billing ledgers, identity) unless it's the actual pain point. Use domain-driven design to identify bounded contexts, and map dependencies in the monolith (code, tables, calls).
Anti-Corruption Layer
When the new service must interact with the legacy system, an anti-corruption layer (ACL) translates between the legacy model and the new domain model. It keeps legacy concepts, naming, and quirks from leaking into the new design. It can live in the new service as adapters, or as a separate translation service.
Data Migration Strategies
Data is usually the hardest part. Options, often combined:
Define one system of record per entity at each stage, and make the ownership transfer explicit. See microservices data management.
Validating Before Switching
- Shadow traffic / dark launching: send copies of real requests to the new service, discard its responses, and compare them with legacy.
- Canary routing: send a small percentage of real traffic, compare metrics, and ramp up. See deployment strategies.
- Feature flags: toggle new paths per user segment, with instant rollback.
- Parity tests: automated comparisons of legacy vs new outputs for representative inputs.
Finishing the Job
The pattern only works if legacy code is actually removed as functionality moves. Otherwise you run two systems indefinitely, with double maintenance cost. Track remaining legacy routes and tables, delete dead code after each migration, and set a decommissioning plan.
Best Practices
Deliver Value at Every Step
Each extraction should ship improvements (faster pages, new features, independent deployments) rather than being pure infrastructure churn. Continuous value keeps the migration funded and supported.
Keep Steps Small and Reversible
Migrate one route, entity, or workflow at a time, with the ability to route back. Small steps limit blast radius and build confidence.
Invest in Observability First
Compare latency, error rates, and business metrics between legacy and new paths. Without good observability, you can't tell whether a migration step helped or hurt.
Improve the Monolith Along the Way
Modularizing the monolith (clear internal boundaries, removed dead code) makes extraction easier, and sometimes a well-structured modular monolith is the right end state. See monolith vs microservices.
Common Mistakes
Big-Bang Rewrite in Disguise
Building the entire new system in parallel before switching any traffic loses the pattern's benefits: no early feedback, no incremental value, and one risky cutover. Route real traffic early.
Never Decommissioning Legacy
Leaving the monolith running "for now" for years means maintaining both systems, keeping data syncs alive, and confusing teams about ownership. Plan and fund removal.
Extracting the Wrong First Service
Starting with the most coupled, critical domain turns the first step into the hardest, often stalling the effort. Pick an achievable, valuable slice first, and build migration capabilities (routing, CDC, observability) along the way.
FAQ
What is the strangler fig pattern?
An incremental migration strategy where new functionality is built alongside a legacy system, and a routing layer gradually shifts traffic from old to new, capability by capability, until the legacy system can be retired. It avoids risky big-bang rewrites.
How do you migrate data in a strangler fig migration?
Usually in stages: keep legacy as the system of record while syncing to the new store (often via change data capture), validate parity, then switch the system of record per entity, possibly syncing back to legacy for remaining consumers, and finally remove the legacy tables. Reconciliation checks throughout catch divergence.
How long does a strangler fig migration take?
It depends on system size and team capacity, often months to several years for large systems. Because each step delivers value and can be paused, the timeline is flexible, but set milestones and decommissioning targets so it finishes.
Do I have to end up with microservices?
No. The pattern works for any replacement: a new monolith, a different framework, a SaaS product, or a cloud platform. Sometimes the right target is a modular monolith, with a few extracted services where independent scaling or deployment truly matters.
Related Topics
- Microservices — The architecture overview
- Monolith vs Microservices — Choosing the target architecture
- Microservices Data Management — Data ownership during migration
- Change Data Capture — Syncing legacy data
- Feature Flags — Safe incremental cutovers
- Technical Debt — Why legacy systems get replaced