Strangler Fig Pattern
The Strangler Fig Pattern incrementally migrates a legacy monolith to microservices by routing traffic to new services one feature at a time, avoiding.
The Strangler Fig Pattern (named after tropical fig trees that envelop their host) incrementally replaces a monolith by routing traffic from old code to new services one feature at a time. Instead of a risky big-bang rewrite, you build new functionality in microservices, redirect traffic via a routing layer, and decommission old code when it is no longer called. This approach is how Amazon, Shopify, and Twitter migrated their monoliths — slowly strangling the old system until it can be removed.
| Aspect | Details |
|---|---|
| What it is | An incremental migration strategy that replaces monolith functionality with new services one feature at a time via a routing layer |
| When to use | Migrating from monolith to microservices, replacing legacy systems, modernizing tech stacks — any situation where big-bang rewrite is too risky |
| When NOT to use | Small, maintainable monoliths where the cost of migration exceeds the benefit, or when the entire system needs replacing rather than incremental migration |
| Real-world example | Amazon spent years strangling their monolith into microservices — each team extracted their service one at a time while the monolith continued serving traffic |
| Interview tip | Describe the routing layer and how it enables gradual cutover without downtime — this shows practical migration experience |
| Common mistake | Trying to strangle too many features at once — the complexity of maintaining both old and new systems simultaneously is high, so migrate one feature at a time |
| Key tradeoff | Safety of incremental migration vs the cost of maintaining two systems in parallel during the transition |
Why This Matters
Big-bang rewrites fail. The 2001 Netscape rewrite took three years and nearly killed the company. The Strangler Fig Pattern avoids this by allowing the old and new systems to coexist. A routing layer (API gateway or reverse proxy) directs traffic: /api/orders goes to the new order microservice, everything else goes to the monolith. Each migration is small, testable, and reversible. If the new service fails, flip the route back to the monolith. This pattern reduces risk to near zero while delivering incremental business value with each migrated feature.
The Building Blocks
- Routing Layer: An API gateway or reverse proxy that directs requests to either the monolith or the new service based on URL path, header, or feature flag.
- Feature Extraction: Identify a bounded context in the monolith, build it as a new microservice, and redirect its traffic. Start with the least coupled, highest-value feature.
- Data Migration: The hardest part. New services need their own data stores, but during transition both old and new may need the same data. Use CDC or dual-writes.
- Parallel Running: Run both old and new implementations simultaneously, comparing results to verify correctness before cutting over. This catches subtle bugs.
- Decommission: Once all traffic flows to the new service and the monolith code path is unused, delete the old code. Never leave dead code in the monolith.
Under the Hood
The migration follows a cycle: identify, build, route, verify, decommission. First, identify a feature boundary in the monolith that is relatively decoupled — user authentication, order processing, or notification sending. Build the replacement as a standalone microservice with its own database. Configure the routing layer to send a percentage of traffic (1%, then 10%, then 100%) to the new service via canary deployment.
The routing layer is the linchpin. In a simple setup, Nginx route rules direct /api/users/* to the new user-service and everything else to the monolith. In a more sophisticated setup, feature flags control per-user routing: internal users get the new service first, then beta users, then everyone. If errors spike, the flag rolls back instantly.
Data migration is the hardest problem. The monolith and new service often need the same data. Strategies include: database view (new service reads from the monolith's database initially — expedient but coupling), CDC (change data capture streams changes from the monolith's database to the new service's database), or dual-write (monolith writes to both databases during transition — risky due to consistency issues). CDC is usually the safest approach.
How Companies Actually Do This
Amazon strangled their monolith over several years in the early 2000s. Each team extracted their service from the monolith, and the API gateway routed traffic gradually. This became the foundation of AWS.
Shopify migrated their Ruby on Rails monolith to microservices using the strangler pattern. They extracted services by domain (checkout, inventory, payments) while the monolith continued serving merchants.
Twitter migrated from their Ruby monolith to JVM-based services. The routing layer directed traffic to new services one endpoint at a time while maintaining 99.99% uptime during the multi-year migration.
Common Pitfalls
- Attempting to migrate too many features simultaneously — parallel migrations create integration complexity that negates the safety benefits of incremental migration
- Not investing in the routing layer — a brittle routing setup makes cutover and rollback difficult and error-prone
- Leaving the monolith in a permanent 'half-strangled' state — without commitment to completing the migration, you end up maintaining two systems indefinitely
Interview Questions Worth Practicing
- How would you plan a strangler fig migration for a 10-year-old monolith with 50 features?
- What is the hardest problem in strangler fig migrations, and how do you solve it?
- How do you handle shared data between the monolith and new microservices during migration?
The Tradeoffs
- Safety vs Speed: Incremental migration is low-risk but takes months or years. Big-bang rewrites are faster but have a high failure rate.
- Dual Maintenance Cost vs Risk Reduction: Running both systems costs more (duplicate infrastructure, two codebases), but each migration step is independently testable and reversible.
- Clean Break vs Coupling: New services that read from the monolith's database are quick to build but create tight coupling. Independent databases are cleaner but require data migration.
How to Explain This in an Interview
Here is how I would explain Strangler Fig Pattern in a system design interview:
The Strangler Fig Pattern migrates a monolith to microservices incrementally — one feature at a time. Instead of a risky big-bang rewrite, I put a routing layer (API gateway) in front of both systems. When I extract user authentication as a new service, the gateway routes /auth/* to the new service while everything else stays on the monolith. I migrate with canary routing: 1% of traffic, then 10%, then 100%, monitoring error rates at each step. If something breaks, roll back the route instantly. The hardest part is data — I use CDC to replicate data from the monolith's database to the new service's database. Each migration is small, testable, and reversible. Amazon used this exact pattern to become the microservices company they are today.
Related Topics
The Real-World Incident That Made This Famous
Understanding Strangler Fig Pattern became critical after multiple high-profile production incidents at major tech companies. When systems handle millions of users, even small misunderstandings about Strangler Fig Pattern can lead to cascading failures that cost millions in lost revenue and erode user trust. Companies like Netflix, Google, Amazon, and Meta have all invested heavily in mastering Strangler Fig Pattern because they learned the hard way that ignoring it leads to outages.
The key lesson from these incidents: Strangler Fig Pattern is not just a theoretical concept — it is a practical skill that separates engineers who build resilient systems from those who build fragile ones. Every major outage report from the past decade involves at least one Strangler Fig Pattern-related design decision that was either implemented incorrectly or overlooked entirely during the initial architecture review.
How Senior Engineers Think About This
Senior engineers approach Strangler Fig Pattern differently from textbook definitions. Instead of memorizing rules, they build mental models. They ask: "What problem does Strangler Fig Pattern solve? When does it fail? What are the alternatives?" This problem-first thinking leads to better design decisions because every system has unique constraints.
When evaluating Strangler Fig Pattern in a system design context, experienced engineers consider the failure modes first. What happens when this component goes down? How does the system degrade? Is the degradation graceful or catastrophic? These questions reveal more about your understanding than any textbook definition.
The key difference between junior and senior engineers when it comes to Strangler Fig Pattern: juniors focus on the happy path, while seniors design for what happens when things go wrong. They consider operational cost, team expertise, monitoring requirements, and how the decision will look six months from now when traffic has grown 10x.
Common Interview Mistakes
Mistake 1: Giving a textbook definition without context. Interviewers want to see you connect Strangler Fig Pattern to real systems and real problems. Instead of reciting definitions, explain when and why you would use Strangler Fig Pattern in the system you are designing.
Mistake 2: Not discussing trade-offs. Every design decision involving Strangler Fig Pattern has trade-offs. Discuss what you gain and what you give up. Acknowledge the downsides and explain why the benefits outweigh them for your specific use case.
Mistake 3: Overcomplicating the solution. Start with the simplest approach to Strangler Fig Pattern that meets the requirements, then add complexity only when justified. Many candidates jump to complex implementations when a simpler solution would work perfectly.
Production Checklist
- Define clear metrics for measuring the effectiveness of your Strangler Fig Pattern implementation
- Set up monitoring and alerting that specifically tracks Strangler Fig Pattern-related failures
- Document your Strangler Fig Pattern design decisions in Architecture Decision Records (ADRs)
- Test failure scenarios related to Strangler Fig Pattern in staging before production deployment
- Review and update your Strangler Fig Pattern implementation quarterly as system requirements evolve
- Train new team members on the specific Strangler Fig Pattern patterns used in your system
- Establish runbooks for common Strangler Fig Pattern-related incidents and recovery procedures
Practical Implementation for .NET Developers
In .NET, use YARP (Yet Another Reverse Proxy) as the routing layer — it integrates natively with ASP.NET Core and supports dynamic route configuration via configuration or code. For feature-flag-based routing, use LaunchDarkly or a custom middleware that reads flags from Redis. For data migration, use Debezium for CDC from SQL Server or PostgreSQL. The monolith can expose internal APIs that the new service calls during the transition period, decoupled via HTTP or messaging with MassTransit.
ASP.NET Core setup: Create a service class that encapsulates the logic, register it with dependency injection, and inject it into your controllers or minimal API endpoints. The built-in DI container handles lifecycle management.
Entity Framework Core: For database interactions, EF Core provides the ORM layer. Use migrations for schema management and raw SQL for performance-critical queries. Consider Dapper for read-heavy paths where EF Core overhead matters.
Azure integration: If deploying to Azure, leverage managed services — Azure Cache for Redis, Azure SQL, Azure Service Bus, Azure Cosmos DB. These eliminate operational overhead and provide built-in monitoring through Application Insights.
Testing: Use xUnit with Testcontainers for integration tests that spin up real databases in Docker. Mock external dependencies with NSubstitute. The WebApplicationFactory class lets you test your entire HTTP pipeline in-process.
Monitoring: Add Application Insights telemetry to track request latency, dependency calls, and custom metrics. Use structured logging with Serilog to make production debugging possible:
Log.Information("Processing {Operation} for {ResourceId}", operation, resourceId);
This gives you searchable, structured logs in Azure Monitor or Seq.