What is the "strangler" pattern for migrating a monolithic application to microservices architecture?

Migrating a large monolithic application to a microservices architecture can feel like changing a plane’s engine mid-flight. The strangler pattern (inspired by the strangler fig tree) offers a safe, incremental way to migrate a monolith to microservices without disrupting users. Instead of a risky “big bang” rewrite, you gradually modernize the system architecture by strangling the old system piece by piece. In this guide, we’ll explain what the strangler pattern is, why companies like Netflix use it, and how you can apply it—complete with best practices, real-world examples, and tips to ace related system design interview questions.

What is the Strangler Pattern?

The Strangler Fig pattern is an architectural approach for gradually modernizing a legacy system. Coined by Martin Fowler in 2004, its name comes from the strangler fig vine that slowly grows around a host tree and eventually replaces it. Similarly, the strangler pattern involves building a new application (often a suite of microservices) around the existing monolith, incrementally replacing the monolith’s functionality until the old system is fully supplanted. It’s a guide for migrating legacy systems to newer architectures gradually, allowing the old and new systems to coexist during the transition.

In practice, this means you don’t rewrite the entire application from scratch. Instead, you peel off features one by one from the monolith into independent microservices. Over time, the new microservices application grows around the monolith (like the fig around the tree) while the monolith’s role shrinks. Eventually, the monolith can be retired once all its features have been replaced by microservices. This approach is often called an “incremental” or “progressive” modernization, and it’s widely recognized as one of the essential microservice design patterns (e.g., it’s featured among the 19 essential microservices patterns for system design interviews on DesignGurus.io).

Why Use the Strangler Pattern for Monolith Migration?

Migrating a critical system is high-stakes, and the strangler pattern’s gradual approach is favored for several reasons:

  • Lower Risk, No Big Bang: Unlike a full rewrite which might take years and could fail to ever launch, the strangler approach delivers changes in small, manageable pieces. New microservices run alongside the legacy system, reducing the risk of a catastrophic cutover. The legacy system keeps working as a safety net (fallback) while new services come online. If something goes wrong with a new component, you haven’t broken the entire system – you can roll back that one piece.

  • Continuous Value Delivery: Each increment provides value on its own. For example, if you pull out one module as a microservice, you can start scaling or updating it independently and potentially deploy new features faster. You don’t have to wait for a years-long project to finish to see benefits. As one DesignGurus blog notes, you get benefits along the way – each new service can be deployed independently with modern tech, delivering improvements to users sooner.

  • Parallel Development and Coexistence: The monolith and microservices coexist during the migration. This means you can modernize parts of the system without freezing all new development. Teams can work on new microservices (using newer tech stacks or architectures) while the rest of the engineering team keeps maintaining other parts of the monolith. The facade or proxy (more on this next) ensures clients continue using the system through one interface, unaware of the behind-the-scenes changes.

  • Knowledge and Requirement Discovery: Modernizing a legacy app is often a journey of discovery – you learn about hidden business logic and outdated features as you go. The strangler pattern accommodates this by allowing an iterative approach. You can prioritize high-value or high-problem areas first (for example, a portion of the code that’s causing most of the scaling issues) and learn from that extraction before tackling other areas. In contrast, a big bang rewrite assumes you know all requirements up front, which is rarely true and can lead to missing critical quirks of the old system.

  • Technical Debt Reduction: By gradually replacing old code with well-designed microservices, you steadily pay down technical debt. Each strangled component is an opportunity to improve or simplify the functionality. Over time, the result is a cleaner, more modular system. You can also upgrade technology incrementally (e.g., move one piece from a legacy framework to a modern one) without breaking the whole product.

It’s no surprise that many industry leaders have embraced the strangler pattern for system modernization. In fact, companies like Netflix, Google, IBM, and Microsoft have all used the Strangler Fig pattern in their large-scale legacy migrations. Let’s look at how the pattern works and how to implement it step by step.

How to Implement the Strangler Pattern (Step-by-Step)

Implementing the strangler pattern involves introducing a routing layer and incrementally carving out functionalities from the monolith. Here’s a step-by-step guide:

  1. Identify a Feature Module to Extract: Start with a specific functionality or domain in your monolith – ideally one that is relatively self-contained or a pain point. For example, an e-commerce monolith might begin by extracting the product catalog or order management component as a separate service. Choosing the right slice is important: some teams pick a small, low-risk module to learn the pattern, while others target a high-impact module that will benefit most from immediate scalability or agility.

  2. Build the New Microservice: Develop a new microservice that implements the chosen feature. This new service will be the “strangler fig” growing around the old system for that functionality. You can write it in a modern language or framework, use its own database (in a microservices architecture each service usually has its own data store), and ensure it meets current requirements. Importantly, keep its external interface (API) consistent with what the monolith exposed for that feature, so that swapping it in is transparent to users.

  3. Introduce a Façade or Proxy Layer: Deploy an API Gateway or some routing mechanism in front of the monolith. This acts as a facade that intercepts incoming requests from clients. At first, most requests still go to the monolith. But for the feature you extracted, the facade will route those specific requests to the new microservice instead. For instance, you might configure the gateway such that any /api/orders/* requests go to the new Order Service, while everything else continues to go to the monolith. This coexist phase lets the new and old implementations run side by side.

  4. Test and Deploy Incrementally: Ensure the new microservice is thoroughly tested. You might run it in shadow mode (processing the same requests as the monolith to compare results) or gradually route a small percentage of live traffic to it, increasing as confidence grows. The goal is to verify that the new service can handle all aspects of the feature correctly. During this phase, users should not notice any difference – the system’s external behavior remains the same, which is a key benefit of the facade approach.

  5. Eliminate the Old Module: Once the new microservice is performing well, you can decommission the equivalent functionality in the monolith. This might mean disabling that code or simply no longer calling it. Traffic for that feature is now permanently routed to the microservice. The legacy application has one less responsibility, and the new system has one more.

  6. Rinse and Repeat: Repeat the process for the next feature or module of the monolith. Over time, you will have migrated multiple chunks of the application into microservices. The facade is continuously updated to redirect additional routes to new services as they come online. The monolith’s footprint shrinks with each iteration.

  7. Retire the Monolith: Eventually, after successive iterations, all important features have been moved off the monolith. At this point, the strangler pattern has “killed” the monolith – it’s no longer needed for production traffic. Now you can decommission the old system entirely. Finally, remove the facade or routing layer, or rather, reconfigure clients to call the new microservice endpoints directly (in some cases the API gateway remains as a permanent entry point, but it no longer needs to deal with any legacy routing). The migration is complete when users and client apps are interacting only with the new microservices system.

Real-World Example: Netflix’s Strangler Fig Migration

To understand the strangler pattern’s benefits, consider Netflix’s approach to modernizing one of its critical systems. A few years ago, Netflix faced the challenge of replacing a “large and complicated legacy system” responsible for media file processing (internally nicknamed “Reloaded”). They needed a new platform (called “Cosmos”) to handle much greater scale and new use cases. Rewriting this system from scratch and switching over in one go would have been extremely risky – any mistake could disrupt streaming for millions of users.

Netflix adopted the strangler fig pattern to reduce that risk. They built the new Cosmos services around the old system and gradually moved workloads to Cosmos piece by piece. As one Netflix engineer noted, the strangler fig approach “lets the new system grow around the old one and eventually replace it completely.” During the transition, the legacy system and new services ran side by side, with Netflix orchestrating which requests went to which system. This incremental migration meant Netflix could test Cosmos in production, migrate functionalities one at a time, and avoid a risky big-bang cutover. By 2021, Cosmos had about 40 microservices and was handling the majority of Netflix’s media processing, with the old system being phased out smoothly.

Netflix’s success story is not unique. Many organizations—especially those with high availability needs—choose the strangler pattern for modernization. It’s a proven approach to gradually overhaul complex, monolithic applications without interrupting service or halting feature development.

Check out 19 essential microservices patterns.

Best Practices for Using the Strangler Pattern

While the strangler pattern provides a blueprint, executing it effectively requires planning. Here are some best practices and tips to ensure a smooth migration:

  • Start with the Right Slice: If you’re new to strangling monoliths, consider starting with a relatively simple, low-risk component to gain experience. This lets your team learn how to split out and integrate a microservice with minimal fallout. Ensure that component has good test coverage and clear boundaries. Alternatively, you can target a high-impact module (e.g. a component that faces scalability issues or frequent updates) so that the benefits of extraction are felt immediately. In either case, clearly define the module’s boundaries (for example, the order management domain) to avoid half-migrating something with tangled dependencies.

  • Use a Robust Facade (Routing) Layer: The strangler pattern relies on a facade or proxy to route requests. Design this layer carefully so it doesn’t become a bottleneck or single point of failure. Many teams use an API Gateway or load balancer for this purpose. Keep routing rules simple and based on clear criteria (like URL paths or message topics). Also, plan for observability in the facade – monitoring which requests go to old vs new systems will help you verify that everything is routing correctly. Remember to update the routing rules as you migrate each new piece. Security and rate-limiting can be enforced here as well, centralizing concerns while you have a mixed architecture.

  • Maintain Data Consistency: One tricky aspect of incremental migration is data. If the new microservice has its own database, consider how it will get the necessary data initially and keep it in sync. Sometimes you might start by letting the new service read from the old database (or a read replica) until you peel that data out. For a period, data might be duplicated or shared between the monolith and microservice, so use event streams, change data capture, or database replication as needed to keep data consistent. Designing clear service boundaries with the single-responsibility principle (each service owns its data) helps minimize cross-talk. But if two systems must touch the same data during coexistence, plan a strategy to reconcile differences (and eventually migrate the data ownership to the new service).

  • Thorough Testing & Monitoring: Testing is your safety net in a strangler migration. Treat each extracted service as a mini-project: write comprehensive unit and integration tests, and perform regression testing against the legacy behavior. Many teams employ a technique of “double-running” – sending requests to both old and new implementations and comparing results – before fully switching over. Canary releases (deploying the new service for a small percentage of traffic) are also valuable. By exhausting each microservice in real scenarios while the monolith still backs it up, you greatly reduce the chances of user-facing issues. As one case study noted, if each microservice is exhaustively tested in normal operations before replacing the old function, you often don’t need any downtime for cutover and can avoid unexpected disruptions. Additionally, set up monitoring and alerts on both the new microservice and the monolith. During coexistence, you want to quickly catch any error rates, latency changes, or other anomalies in either system. Good observability ensures you know if something goes wrong before turning off the old code.

  • Gradual Decommission and Clean-up: As you migrate feature by feature, periodically remove or disable the old code that has been replaced. This keeps the monolith leaner (improving its performance and reducing confusion about which parts are active). It’s also a morale boost to see the monolith shrinking! However, maintain a rollback plan for each migration step. For example, you might leave the old code in place but gated, so if the new service encounters a severe issue, you can quickly route back to the monolith for that feature. Once confidence is high, fully remove the old code to avoid clutter and drift. Only when all pieces are moved and stable should you finally remove the facade/gateway (or simplify its config) and declare the migration complete.

  • Don’t Strangle Forever: Set goals and timelines for the migration. One risk of incremental approaches is that they can stall – you migrate a few services and then stop, ending up maintaining a half-monolith/half-microservices Frankenstein indefinitely. Avoid this by prioritizing the remaining pieces and keeping the momentum until you’ve modernized what you set out to. If certain parts of the old system are low-value and never justify moving, you might decide to leave them as-is (perhaps isolating them behind an API). But in general, a successful strangler migration has an endgame where the legacy is fully retired. Keeping executive and team buy-in by demonstrating success in early phases will help ensure you get to the finish line.

By following these best practices, you leverage the strangler pattern to its fullest potential—gradually refactoring your system with control and confidence. It’s a powerful technique for architects and engineering teams looking to rejuvenate legacy systems while continuing to deliver value to users.

Frequently Asked Questions

Q1. What is the strangler fig pattern in microservices?

The strangler fig pattern is a gradual migration strategy for legacy applications. It involves wrapping a monolithic application with new microservices and slowly replacing pieces of the monolith with those services. Over time, the new microservices application grows around the old system, eventually taking over all functionality so the monolith can be safely retired. This approach lets you modernize an application incrementally without a big-bang rewrite.

Q2. Why is it called the “strangler fig” pattern?

It’s named after the strangler fig, a vine that germinates on a host tree and gradually envelops and replaces it. Martin Fowler coined the term after observing this in nature. In software, the legacy monolith is like the host tree and the new microservices are the fig vines. As you add more microservices (the vines) around the old system, they “strangle” the monolith by taking over its responsibilities, until eventually the legacy system is completely replaced by the new one.

Q3. How do you implement the strangler pattern step by step?

Implementation is typically done in three phases: Transform, Coexist, and Eliminate. First, identify a part of the monolith and create a new microservice to handle that functionality (Transform). Next, deploy a façade or API gateway so that the monolith and new service run in parallel – route relevant requests to the microservice while other traffic still goes to the monolith (Coexist). Finally, once the new service is stable, decommission that feature in the monolith and direct all requests to the microservice (Eliminate). You then repeat this process for other modules until the entire monolith has been migrated to microservices.

Q4. What are the benefits of using the strangler pattern versus a full rewrite?

The strangler pattern minimizes risk compared to a wholesale rewrite. You can deliver improvements iteratively instead of waiting for a multi-year project to finish. Each new microservice can be developed and deployed independently (often with better technology or architecture) to solve a specific problem. If a new service encounters issues, the rest of the system remains unaffected, as the legacy monolith still handles other functions as a fallback. This approach also allows prioritizing critical parts of the system first (e.g., strangling the most painful legacy component early). In short, you get faster value delivery, safer updates, and the flexibility to modernize at your own pace.

Q5. What are the challenges or drawbacks of the strangler pattern?

While powerful, the strangler approach isn’t a silver bullet. Running a monolith and microservices in parallel adds complexity – your team has to manage two systems and ensure they stay in sync. There can be performance overhead (more network calls between services) and potential for a facade or gateway to become a bottleneck if not designed well. Data consistency is a common challenge; you must synchronize data between the old and new systems during migration to avoid inconsistencies. The pattern may not be worth it for small applications with low complexity – in those cases, a simple rewrite or refactor might be easier. Additionally, if you cannot intercept and route requests (for example, if external clients directly access the legacy system’s modules in a way you can’t proxy), then implementing the strangler pattern is difficult. Finally, incremental migrations require discipline and good planning; without clear goals, there’s a risk of stalling partway and having to maintain a hybrid system longer than intended. Having a solid strategy and buy-in from stakeholders is key to overcoming these challenges.

Conclusion

The strangler pattern offers a pragmatic path to modernize legacy applications by gradually transitioning from a monolithic architecture to microservices. By mimicking the strangler fig tree, it lets you replace the old system piece by piece – delivering value at each step and avoiding the risks of a big bang rewrite. Key takeaways include starting small, ensuring old and new systems run concurrently with proper routing, and systematically decommissioning legacy components as you go. This approach not only results in a more scalable and maintainable system, but also demonstrates strong architectural foresight – a quality highly valued in system design discussions and technical decision-making.

By understanding this pattern, you’ll be better prepared to tackle real-world modernization projects and to impress in system design interviews. To dive deeper and get hands-on experience, consider exploring our courses like Grokking Microservices Design Patterns and Grokking Design Patterns for Engineers and Managers. These courses provide expert insights, real-world examples, technical interview tips, and even mock interview practice to solidify your learning. Sign up today to level up your system design skills – invest in your growth and join the community of developers mastering the art of modern system architecture. Good luck on your journey to strangling that monolith, and happy designing!

CONTRIBUTOR
Design Gurus Team
-

GET YOUR FREE

Coding Questions Catalog

Design Gurus Newsletter - Latest from our Blog
Boost your coding skills with our essential coding questions catalog.
Take a step towards a better tech career now!
Explore Answers
Related Courses
Grokking the Coding Interview: Patterns for Coding Questions
Grokking the Coding Interview Patterns in Java, Python, JS, C++, C#, and Go. The most comprehensive course with 476 Lessons.
Grokking Modern AI Fundamentals
Master the fundamentals of AI today to lead the tech revolution of tomorrow.
Grokking Data Structures & Algorithms for Coding Interviews
Unlock Coding Interview Success: Dive Deep into Data Structures and Algorithms.
Image
One-Stop Portal For Tech Interviews.
Copyright © 2025 Design Gurus, LLC. All rights reserved.
;