Strangler Fig Pattern
Architecture Diagram
How the Pattern Works
The strangler fig tree grows around an existing tree, eventually replacing it entirely. Martin Fowler named this pattern after observing these trees in Australia, and the metaphor is precise: you build a new system around the old one, migrating functionality piece by piece until the old system can be shut down.
The key component is a facade (or proxy) that sits in front of both systems. It receives all incoming requests and routes them to either the legacy system or the new system based on the URL path, header values, or other routing rules. Nginx, Envoy, or an API gateway works well for this. The facade starts by routing 100% of traffic to the legacy system. As you migrate each route, you update the facade to send that route's traffic to the new system.
Step-by-Step Approach
Step 1: Identify boundaries. Map the legacy system's routes, data flows, and dependencies. Group related routes into migration units. A migration unit should be small enough to complete in 2-4 weeks.
Step 2: Deploy the facade. Put a reverse proxy in front of the legacy system. Initially, it passes everything through unchanged. This step validates that the proxy layer works without changing any behavior.
Step 3: Migrate one route. Build the new implementation for a single route. Deploy it alongside the legacy system. Configure the facade to route that specific path to the new system.
Step 4: Verify parity. Run both implementations in parallel using shadow traffic or dual-write comparison. Log every divergence. Investigate and fix differences until outputs match. Shopify used this approach when migrating from a monolithic Rails app, running shadow traffic for weeks per route.
Step 5: Cut over and decommission. Once parity is confirmed, update the facade to route production traffic to the new system. Monitor closely for 1-2 weeks. Then remove the route from the legacy system. This last step is critical and often skipped.
Anti-Corruption Layers
The legacy system has its own domain model, naming conventions, and data formats. The new system should not adopt these. An anti-corruption layer (ACL) sits between the facade and the new system, translating legacy request formats into the new system's domain language.
Without an ACL, the new system becomes a translation of the old system rather than an improvement. You end up with legacy field names, legacy data structures, and legacy assumptions baked into fresh code. The ACL is a small investment that pays off by keeping the new system clean.
Event Interception vs API Interception
There are two approaches to routing through the facade. API interception routes HTTP requests at the proxy level. This works for request-response interactions and is the most common approach.
Event interception captures events from the legacy system (database changes via CDC, message queue publications) and processes them in the new system. This is necessary when the legacy system publishes events that downstream consumers depend on. During migration, both systems may need to publish to the same event streams.
Timeline and Organizational Reality
The technical execution is usually straightforward. The organizational challenge is maintaining momentum over 12-24 months. Legacy migrations compete with feature work for engineering time. Without executive sponsorship and dedicated headcount, migrations stall at 60-70% completion. The remaining 30% contains the hardest, most entangled parts of the system.
Set milestones every 6-8 weeks and report progress in business terms: "We migrated checkout, which processes $2M daily." This keeps stakeholders engaged and justifies continued investment.
Key Points
- •The strangler fig pattern replaces a legacy system incrementally by routing traffic through a facade that delegates to either the old or new system per route
- •Start with the highest-value, lowest-risk routes. A read-only endpoint with clear inputs and outputs is a better first migration target than a complex transactional workflow
- •Anti-corruption layers translate between the legacy system's domain model and the new system's model. Without this boundary, the new system inherits legacy assumptions
- •Parity verification is non-negotiable. Run both systems in parallel and compare outputs before cutting over each route. Differences reveal undocumented behavior
- •Expect the migration to take 12-24 months for a system of significant size. Plan for this timeline and secure organizational commitment upfront
Common Mistakes
- ✗Trying to understand the entire legacy system before starting migration. You will never fully understand it. Start with one route, learn as you go, and iterate
- ✗Building the new system as a complete rewrite behind the facade instead of migrating incrementally. This defeats the purpose of the pattern and reintroduces big-bang risk
- ✗Neglecting to decommission migrated routes from the legacy system. Without active decommissioning, you end up maintaining two systems indefinitely
- ✗Underestimating the undocumented behavior embedded in the legacy system. Edge cases that nobody remembers will surface during parity testing