Strangler Fig
“The most important thing to do is find a way to nibble at it.” — Martin Fowler
Replace a legacy system incrementally by building new functionality alongside it, routing traffic piece by piece, until the old system can be switched off.
Also known as: Strangler Fig Application, Strangler Pattern, Incremental Modernization
Understand This First
- Refactor – the discipline of improving structure without changing behavior, which Strangler Fig applies at the system level.
- Migration – moving from one system to another; Strangler Fig is a strategy for doing it safely.
Context
You’re working with a system that has been running in production for years. It works, mostly. It also carries years of accumulated complexity, outdated technology choices, and technical debt that makes every change expensive. You need to modernize it, but you can’t stop shipping features while you build a replacement from scratch.
Problem
You need to replace or modernize a legacy system, but a full rewrite is too risky. Rewrites fail for predictable reasons: they take longer than estimated, the team must maintain two systems in parallel, and the new system must replicate every behavior of the old one, including the undocumented behaviors nobody remembers. During the rewrite window, no new features ship. Meanwhile, the old system keeps accumulating new requirements and new debt, so the target keeps moving.
How do you replace a running system without stopping it?
Forces
- A full rewrite means maintaining two parallel systems until the new one is complete, doubling the operational burden.
- The old system’s behavior is the specification, and much of it is undocumented or discovered only when something breaks.
- Business can’t pause feature delivery for the duration of a rewrite.
- Each module has different replacement urgency. Some are fine; others are acutely painful.
- Testing a replacement against a live system is harder than testing greenfield code in isolation.
Solution
Build the new system around the old one, replacing it one capability at a time. The name comes from the strangler fig tree, which germinates in the canopy of an existing tree, sends roots down to the ground, and gradually envelops the host until the host dies and the fig stands on its own.
The technique has three phases:
Intercept. Place a routing layer between the system’s consumers and the legacy implementation. This could be a proxy, an API gateway, a facade, or a feature flag. Initially it forwards everything to the old system unchanged. Its job is to give you a point of control where you can redirect traffic without touching the consumers.
Replace. Pick one capability, build the new implementation, and route that capability’s traffic through the routing layer to the new code. The old code still exists but no longer receives requests. Run both paths in parallel if you need to verify that the new implementation matches the old one’s behavior.
Remove. Once the new implementation has proven itself in production, delete the old code for that capability. Go back to Replace for the next one.
Which capability do you start with? Two common strategies: pick the most painful module (biggest relief earliest) or the easiest one (builds confidence and establishes the pattern). Either beats trying to replace everything at once.
How It Plays Out
An e-commerce company runs order processing on a monolith built a decade ago. Pricing, tax calculation, inventory checks, and payment processing all live in the same checkout module. The team puts a thin API gateway in front of the monolith and routes all checkout requests through it. First they extract tax calculation into a new service. The gateway sends tax requests to the new service; everything else still hits the monolith. After two weeks of production traffic proving the new service correct, they delete the tax code from the monolith. Then pricing. Six months later the monolith handles only payment processing, the last piece to migrate. The checkout flow never went down, and the team never stopped shipping features.
An agentic team takes a different angle. They point an agent at the legacy codebase and ask it to map public interfaces, trace the call graph for a specific capability, and generate a facade that replicates the old interface while delegating to a new implementation behind it. The agent reads the existing code, produces the facade and a new implementation with tests, and the team reviews the output. Because the facade preserves the old interface, nothing else needs to change yet. Next the agent generates integration tests that call both the old path and the new path with identical inputs and compare outputs. Once those tests pass across a broad input set, the team flips the routing layer. The agent compressed weeks of manual code archaeology into days, but the strategy was the same: intercept, replace, remove.
When using agents for strangler fig migrations, have the agent write comparison tests that exercise both the old and new code paths with identical inputs. The tests become the proof that the replacement is safe to switch over.
Consequences
Strangler Fig reduces modernization risk by making each step small, reversible, and independently verifiable. You never bet the system on a single cutover. If a new component fails, you route traffic back to the old one while you fix it.
The tradeoff is operational complexity. You’re running two implementations of some capabilities simultaneously, and the routing layer itself is new infrastructure that needs monitoring. The migration also takes longer than a clean rewrite would in theory, though rewrites rarely finish on time in practice.
There’s a subtler risk: teams that start a strangler fig sometimes leave it half-finished, running a hybrid system indefinitely because the remaining modules are “good enough.” This hybrid state is stable but carries its own maintenance burden, and each unconverted module makes the next conversion feel less urgent.
Related Patterns
- Depends on: Refactor – strangler fig is refactoring at the system level, replacing internal structure while preserving external behavior.
- Depends on: Migration – each replacement step is a migration of one capability from old to new.
- Mitigates: Technical Debt – one of the few strategies that can address debt accumulated at the architectural level.
- Uses: Interface – the routing layer works because it preserves the existing interface, decoupling consumers from implementation.
- Uses: Contract – the old system’s behavior is the implicit contract the new system must honor.
- Uses: Feature Flag – feature flags are one mechanism for the routing layer, enabling gradual cutover.
- Uses: Test – comparison tests between old and new implementations are the safety net that makes each replacement step trustworthy.
- Avoids: Big Ball of Mud – strangler fig is an escape route from mud; rewriting risks creating new mud.
- Related: Rollback – the routing layer gives you a rollback mechanism at the capability level.
- Related: Boundary – the routing layer introduces a clear boundary between old and new implementations.
- Related: API – an API gateway is a common implementation of the routing layer.
- Related: Decomposition – strangler fig decomposes a monolith incrementally rather than all at once.
Sources
Martin Fowler introduced the Strangler Fig Application pattern in a 2004 blog post, inspired by strangler fig trees he observed in a rainforest. The metaphor captures the core idea: new growth wraps around the old structure until the old structure is no longer needed.
Michael Feathers described the broader discipline of working with legacy code in Working Effectively with Legacy Code (2004), providing techniques for getting existing code under test before replacing it. His methods address the prerequisite problem: how do you gain enough confidence in the old system’s behavior to know your replacement is correct?
Sam Newman extended the pattern for microservice migrations in Monolith to Microservices (2019), detailing practical routing strategies, data migration techniques, and the organizational dynamics of incremental decomposition.