Strangler Fig Pattern: A Practical Guide to Legacy Migration

Rewriting a legacy system from scratch sounds appealing until you're six months into a "big bang" rewrite with nothing shippable to show for it. The strangler fig pattern exists because that failure mode is so common: teams replace a legacy system gradually, behind a facade, instead of betting the business on a single cutover. This guide covers how the pattern works, where it breaks down in practice, and how to decide what to migrate first, the part most explanations skip entirely.
What Is the Strangler Fig Pattern?
The strangler fig pattern is a migration strategy that incrementally replaces a legacy system by routing traffic through a facade to new services, one piece of functionality at a time, until the legacy system can be fully decommissioned. Instead of one risky cutover, the old and new systems run side by side, and the facade decides which one handles each request.
Where the Name Comes From
Martin Fowler coined the term after seeing strangler fig vines in the rainforests of Queensland: "These are vines that germinate in a nook of a tree. As it grows, it draws nutrients from the host tree until it reaches the ground to grow roots and the canopy to get sunlight. It can then become self-sustaining, and its original host tree may die, leaving the fig as an echo of its shape." Fowler's original bliki post is still the clearest statement of the idea, and most of what's written about the pattern today, including this guide, works from his framing. The analogy holds up well for software: the new system grows around the edges of the old one, taking on more workload over time, until the legacy system quietly disappears. Wikipedia also notes an alternate name, the Ship of Theseus pattern, borrowed from the philosophical paradox about identity through gradual replacement.
How the Strangler Fig Pattern Works
The mechanics are simpler than the metaphor suggests. A facade, or proxy layer, sits between the client app and the back-end systems, intercepting every request and deciding whether the legacy system or the new system should handle it. Ideally, the client's contract stays stable, though latency, auth, error shapes, and edge cases can still shift underneath it unless the facade and new service are contract-tested against each other.
The Facade / Proxy Layer
The facade is the load-bearing piece of the whole pattern. Early in a migration, it routes almost everything to the legacy system, since almost nothing has moved yet. As new services come online, the facade's routing rules shift traffic toward them, endpoint by endpoint or domain by domain. Teams often build this on an API gateway, since gateways already route, authenticate, and observe traffic at the edge.
Incremental Decomposition (Shifting Functionality Piece by Piece)
Decomposition happens in thin slices, not big chunks. A team picks one piece of functionality, usually something bounded and low-risk, builds it as a new service, points the facade at it, and validates that it behaves correctly under real traffic before moving to the next slice. This is where teams get stuck: picking the next slice requires knowing which parts of a legacy system are safe to touch, which is rarely obvious from the outside.
Decommissioning the Legacy System
The pattern reaches its endpoint once every piece of functionality has moved and nothing still depends on the old system. At that point, the facade routes exclusively to the new system, and both the legacy system and the facade itself can be retired. This last step gets delayed more often than any other, because "nothing depends on the old system anymore" is a harder claim to verify than it sounds in large organizations where dependencies aren't fully documented. Before calling a slice done, check a few concrete exit criteria: no live traffic hitting the legacy route, no consumers or reporting jobs still reading from it, historical data handled, monitoring confirming zero usage, and the rollback window closed.
How the strangler fig facade works, visualized:

Strangler Fig Pattern vs. Big Bang Rewrite
The strangler fig pattern exists as an alternative to the "big bang" rewrite, where a team builds a full replacement in isolation and cuts over all at once. Big bang rewrites aren't inherently wrong, they're just a different risk profile: all the transformation risk compresses into a single cutover event, and the business gets no incremental value until that event succeeds.
That lower disruption isn't free: strangler fig trades cutover risk for coexistence risk, routing complexity, synchronization lag, and a rollback path that gets harder the longer both systems run side by side.
The trade-off is time and complexity. A strangler fig migration usually takes longer end-to-end than a rewrite would in a perfect world, because it carries transitional architecture (facade, sync logic, dual-write code) for the duration. Fowler acknowledges this cost directly, noting that teams "balk at the necessity of building transitional architecture to allow the new and legacy system to coexist, code that will go away once the modernization is complete," but argues the reduced risk and earlier value outweigh it. For production systems with real users and real revenue on the line, that trade is usually worth making.
Strangler Fig Pattern and Microservices
The strangler fig pattern is most often discussed in the context of monolith-to-microservices migrations: it's the usual mechanism for getting there without stopping the business. But the pattern itself doesn't tell you where to draw service boundaries, and getting that wrong is one of the more expensive mistakes a migration can make.
AWS is pretty blunt about this in their guidance, remarking that "The premature decomposition of systems can be costly, especially when the domain isn't clear, and it's possible to get the service boundaries wrong." Their recommendation is domain-driven design and event storming to determine domain boundaries before decomposing. Teams that skip this step tend to end up with services that mirror the old codebase's accidental structure instead of the actual business domain, which just moves the tangle from one system to another.
An anti-corruption layer does complementary but different work: the facade routes incoming traffic between legacy and new systems, while the anti-corruption layer translates between the legacy data model and the new service's model once a request arrives. The two often work together, but one isn't a substitute for the other. If you're weighing whether microservices are the right target architecture at all, our guide on moving from a monolith to microservices covers that decision in more depth.
Benefits of the Strangler Fig Pattern
The core benefit is risk reduction, but it shows up in a few concrete ways:
- Reduced risk per release. Each slice is small enough to test, validate, and roll back independently.
- Earlier value delivery. New functionality reaches users as each slice ships, not on a single release date months out.
- Continuous delivery stays intact. Teams keep shipping other features instead of freezing the roadmap for a rewrite.
- Business continuity. The legacy system keeps serving traffic for everything that hasn't moved yet, so customers don't feel a hard cutover.
The pattern doesn't eliminate risk so much as spread it out, making each piece small enough to manage.
Challenges and Considerations
The two biggest risks with this pattern are well documented, and both are worth planning for before they show up in production.
When the Facade Becomes a Bottleneck
The facade sits in the request path for every single call during the migration, which makes it a natural candidate for a single point of failure or a performance bottleneck if it isn't built and scaled carefully. Microsoft and AWS both flag this directly. Treating the facade as production infrastructure from day one, with its own monitoring, capacity planning, and failover, avoids a lot of pain later.
Data Synchronization Between Old and New Systems
The messier problem is usually data, not routing. When a new service needs data that still lives in the legacy monolith's database, something has to keep the two in sync. AWS describes introducing "a synchronizing agent between the user microservice and the monolithic database," with the caveat that "the data in the monolithic database is eventually consistent for the data that is being synchronized." Thoughtworks goes further, warning that keeping the same data current in both systems during the transition "can be complex and error-prone." Routing is usually the easy part; reconciling two sources of truth is where teams underestimate the work.
AWS's synchronizing agent is one option, not the only one; change-data-capture, a read-through API, batch backfills, an outbox pattern, or temporarily sharing a datastore can be more realistic for a given slice. Whichever mechanism you use, plan for a clear source of truth per slice, failed-sync handling, idempotent reconciliation, replay after outages, and how schema drift and eventual consistency get surfaced to users and support.
There's also a governance risk that's easy to miss: "temporary" infrastructure nobody is tracking has a way of becoming permanent. If no one owns the decision of when a slice is "done," that transitional code just accumulates.
When to Use the Strangler Fig Pattern (and When Not To)
The pattern earns its complexity when a system is large, business-critical, and can't tolerate downtime or a risky cutover. It's a weaker fit in a few specific situations. Microsoft's guidance lists these directly: when requests to the back end can't be intercepted, when you don't have access to the legacy system's source code, when the system is small enough that a full replacement is simple, or when you need to fully decommission the original system quickly. In any of those cases, the overhead of building and maintaining a facade doesn't pay for itself.
The practical version of this decision comes down to two questions: how much does a failed cutover cost you, and how confident are you in the legacy system's boundaries? If the answer to the first is "a lot" and the second is "not very," the strangler fig is often the safer bet once you've identified workable seams to split along; without those seams, spend time on discovery and modularization first.
How to Implement the Strangler Fig Pattern: A Step-by-Step Example
The following is an illustrative, hypothetical example, not a real case study, showing how the mechanics play out in practice. It mirrors the shape of the worked examples AWS and Thoughtworks use in their own guidance.
Imagine a monolithic e-commerce application with a shared relational database, similar in shape to the example AWS uses: a user service, a cart service, and an account service, where the cart service depends on the user service. The team wants to migrate this monolith to microservices, and the checkout API is the first thin slice. Checkout is revenue-critical and tightly coupled to payments, inventory, tax, and fraud checks in many real systems, so this only works as a first slice because clear boundaries already exist here; otherwise, a lower-risk slice is the safer start.
1. Stand up the facade. Place an API gateway in front of the monolith. Initially, it routes 100% of traffic to the legacy system, so nothing changes for users yet.
2. Build the new checkout service in isolation. The new service gets its own database and deployment pipeline, decoupled from the monolith's release cycle.
3. Add a synchronizing agent. The new checkout service needs order and user data that still lives in the monolithic database, so a synchronizing agent keeps the new data store consistent with the legacy source of truth.
4. Prove equivalence, then route a slice of traffic to the new service. Contract tests confirm the new service matches legacy behavior, and route-level telemetry is in place, before the facade starts sending checkout requests to it, often gated by a feature flag, while every other endpoint still goes to the monolith.
5. Validate, then expand. Once the new checkout service proves stable under real traffic, the team moves to the next slice, maybe the cart service, and repeats the process.
6. Retire the legacy component and update the facade. Once nothing depends on the legacy checkout code, it's removed, and the facade's routing rules for that endpoint are simplified or eliminated.
Repeated slice by slice, this is the entire pattern. What changes each time is the harder question: which slice to migrate next, and why.
Deciding and Governing Strangler Fig Migrations with Catio
That last question, deciding what to strangle first, is the part most technical guides spend the least time on. Microsoft, AWS, and Thoughtworks each offer some criteria for a first slice, but none turn that into a repeatable way to prioritize across a large, poorly documented legacy estate. Thoughtworks' own case study gets closest, noting the team picked their first slice because it was "heavily used" but "not as complex as the other pieces," a reasonable instinct but not a repeatable process.
This is where Catio, the Architecture IDE, fits. We aren't a tool that executes a strangler fig migration; your coding tools and frameworks still do that work. It sits above the migration as a control plane for legacy modernization, a continuous system for understanding your architecture, deciding what gets built, and keeping systems aligned as they evolve. That's the layer most strangler fig write-ups leave out.
In practice, that looks like our product loop: Understand, Decide, Design, Execute, Compound, mapped onto a migration. You understand the current architecture and its dependencies, decide which components to strangle first based on risk and business value, then design the target state for that slice. Execution still happens in your own tools: we're explicit about that boundary: "We don't replace coding IDEs. We define what gets executed at the system level."
Deciding what to strangle first, visualized:

Two capabilities matter here specifically. Archie, Catio's reasoning agent, helps architects work through which legacy components to peel off first, with trade-offs attached, rather than relying on a gut call. Rather than acting as a generic chatbot, Archie works from the architectural model built from your workspace, reasoning through dependencies and constraints and asking clarifying questions to narrow in on what you actually need, though how complete that picture is depends on what's connected and configured.
Blueprints turn a proposed slice into a structured artifact: a documented change from current state to target state, with reasoning, business impact, and an implementation path attached. That structure fits a migration broken into sequential slices well, since each slice can become its own Blueprint with its own scope.
That context doesn't have to stay locked in a separate tool once execution starts. We connect to MCP-compatible coding tools, with Claude Code documented as the reference client, so once connected and authorized, architecture context and specs behind a Blueprint can flow into the tool a developer uses to build the slice. That closes a gap the pattern itself never addresses: the decision behind a slice and the code that implements it usually live in different places, and the reasoning behind why a slice was scoped that way gets lost within months.
This also speaks to the governance risk covered earlier: transitional architecture quietly becoming permanent. A migration tracked as a sequence of decisions, rather than a pile of temporary code, is easier to audit later, since you can see which slices are done and which facade routes are safe to retire. For a broader look at sequencing a full modernization effort, see our guide to legacy system modernization.
Conclusion
The strangler fig pattern reduces migration risk by replacing a legacy system incrementally behind a facade instead of betting everything on a single rewrite. The mechanics (facade, thin slices, eventual decommissioning) are well documented and don't change much from one migration to the next. What's harder is deciding what to strangle first and keeping that decision visible as the system evolves.
If the harder question for your migration is sequencing, not mechanics, our Architecture IDE is built for that layer: understanding your current architecture, deciding which components to strangle first, and keeping that decision compounding as your system changes. If the strangler fig is one piece of a larger modernization push, rearchitecting the stack for the AI era is worth reading next.
FAQ
What are the benefits of using the strangler fig pattern?
Reduced risk per release, earlier delivery of value since each migrated slice ships independently, and business continuity, since the legacy system keeps serving traffic for everything that hasn't moved yet. It also avoids the all-or-nothing failure mode of a big bang rewrite.
What are the challenges of using the strangler fig pattern?
The facade becoming a single point of failure or performance bottleneck if it isn't built for production load, and data synchronization between the legacy and new systems during the transition, which both AWS and Thoughtworks describe as complex and error-prone. A less discussed but equally real challenge: transitional architecture that was meant to be temporary quietly becoming permanent because nobody tracked it.
How does the strangler fig pattern relate to microservices architecture?
It's the most common mechanism for migrating a monolithic application to a microservices architecture incrementally, decomposing a system piece by piece behind a facade instead of rewriting it all at once. The pattern itself doesn't define service boundaries; that typically comes from domain-driven design work done alongside the migration.
What is the strangler fig pattern in one sentence?
A legacy migration strategy where a facade routes traffic between an old system and a new one, letting teams replace functionality piece by piece until the old system can be safely retired.


