What Is the Strangler Fig Pattern?
The strangler fig pattern is a software design approach used to gradually replace or modernize legacy systems. Instead of attempting a risky, full-scale rewrite, new functionality is built alongside the old system. Over time, parts of the legacy system are incrementally replaced until the old system can be fully retired.
The pattern gets its name from the way a strangler fig plant grows around a tree: it slowly envelops and eventually replaces the host without killing it abruptly. In software, this minimizes disruption and allows continuous delivery of new features. The strangler fig pattern is often used in large, complex applications, where rewriting the system from scratch would be costly or risky.
This is part of a series of articles about legacy code
Core Principles of the Strangler Fig Pattern
Incremental Replacement
Incremental replacement focuses on building new functionality outside the legacy system instead of modifying the existing code. New features are developed as separate modules or services and then integrated into the overall system through careful routing. This approach reduces the risk of system-wide failures because only small parts are changed at a time.
Teams can prioritize which parts of the legacy system to replace based on business needs, system complexity, or performance issues. It also allows for quick wins, where small but important improvements can be delivered faster.
Proxy or Façade Layer
A proxy or façade acts as an entry point that hides the complexity of routing requests between the legacy system and the new modules. It can be implemented at the application level, API gateway, or network level depending on the system’s architecture. By intercepting requests, the proxy decides whether to handle them using the old system or the new services.
This decouples the user experience from the underlying technology changes. It also makes it possible to switch traffic gradually—testing new services with a small group of users first before fully rolling them out.
Coexistence
For much of the migration process, both the legacy system and the new services need to work side by side. This requires careful planning to ensure data consistency, transaction integrity, and a seamless user experience. Sometimes, dual writes (writing to both old and new systems) or synchronization mechanisms are necessary to keep data aligned.
During coexistence, monitoring is critical to detect issues early. This phase may last months or even years in very large systems, and it requires strong operational discipline to manage two evolving systems.
Elimination
As new services prove reliable and fully replicate the old functionality, the corresponding parts of the legacy system can be decommissioned. Elimination should be handled systematically, with careful validation to ensure nothing critical is lost. Removing old code, databases, and infrastructure reduces the system’s maintenance burden and operational risks.
This phase delivers the long-term benefits of the migration: improved scalability, flexibility, and lower technical debt. A complete elimination marks the successful end of the strangler fig migration.
When to Use the Strangler Fig Pattern
There are several instances when organizations or development teams may opt for this pattern.
Unsustainable Development
Legacy systems often reach a point where even minor changes become risky and time-consuming. Technical debt accumulates over the years, creating fragile codebases that are difficult to test, debug, and extend. As a result, teams may spend more time fixing regressions than delivering new features.
The strangler fig pattern offers a structured way to escape this trap. By building new functionality separately and slowly replacing legacy components, teams can bypass the risks tied to the old system. This approach enables continuous delivery of new features while gradually reducing the complexity and fragility of the legacy code.
Unexpected Growth
Systems built for a narrow audience or simple workflows can become overwhelmed when the user base or business demands grow unexpectedly. Features that once worked fine under limited load may buckle under increased traffic, larger data volumes, or new operational needs. The underlying architecture may not have been designed for scalability or modularity.
In such cases, rewriting the entire system would delay critical improvements. Instead, the strangler fig pattern allows organizations to address the most urgent scalability issues incrementally. Teams can replace or rearchitect modules — such as authentication, data storage, or reporting — without touching the rest of the system.
Demand for Parallel Development
Legacy monoliths often have tightly coupled components, making it hard for multiple teams to work independently. Changes to one part of the system can create unexpected side effects elsewhere, forcing teams into serialized, slow development cycles. This structure bottlenecks innovation and creates dependencies that slow down releases.
The strangler fig pattern solves this by creating clear boundaries between new and old parts of the system. As teams strangle parts of the monolith into separate services or modules, they gain autonomy to work in parallel. Teams can adopt new technologies, release independently, and iterate faster without waiting for global updates or worrying about breaking the application.
Tech Obsolescence
Software platforms, programming languages, and libraries evolve rapidly. A legacy system built on obsolete technologies often faces growing operational risks, security vulnerabilities, and a shrinking pool of developers who can maintain it. Outdated technology can also miss out on the advantage of newer capabilities like cloud-native infrastructure or AI integration.
Attempting to rewrite the entire system on new technology stacks in one big effort can be prohibitively risky. The strangler fig pattern offers a safer route: teams can gradually adopt new technologies one service or module at a time. For example, a legacy on-premise database could be replaced with a cloud-native alternative, or an outdated web frontend could be modernized using a new framework.
Related content: Read our guide to working with legacy code
Tips from the expert:
Pros and Cons of the Strangler Fig Pattern
The strangler fig pattern offers several advantages that make it a popular approach for modernizing legacy systems. Its incremental nature and focus on minimizing risk are particularly valuable for large, complex projects.
Key benefits include:
- Reduced risk: Changes are made gradually, limiting the blast radius of any issues and avoiding the dangers of a full system rewrite.
- Continuous delivery: New features and improvements can be rolled out while modernization work is ongoing, keeping business initiatives moving forward.
- Incremental investment: Costs are distributed over time, allowing organizations to align modernization work with budget cycles and shifting business priorities.
- Faster learning and feedback: Working in small steps enables teams to detect problems early, adjust strategies, and learn about legacy system behaviors in real-world conditions.
- Improved system understanding: Dealing with the system component by component deepens the team’s knowledge, leading to better architectural decisions during the transition.
However, the pattern also introduces new challenges that teams must manage carefully. Without good discipline and planning, the migration process can drag out or introduce new operational risks.
Some of the main drawbacks are:
- Operational complexity: Managing a hybrid environment of legacy and new systems increases system complexity and operational overhead.
- Longer timeframe: Incremental migrations usually take much longer than rewriting everything at once, extending the period of dual maintenance.
- Temporary technical debt: The need for bridging code, synchronization layers, and integration solutions can accumulate technical debt if not cleaned up later.
- Requires strong discipline: Teams must stay focused and systematic; otherwise, the migration can stall indefinitely, leaving the organization with two partially modernized systems.
- Potential performance overhead: Proxies, façade layers, and integration mechanisms can add latency and reduce system efficiency if not properly optimized.
Key Challenges in Applying the Strangler Fig Pattern
Organizations should be aware of the potential challenges before choosing this development pattern. Here are some of the main challenges.
Synchronizing Data Across Systems
One of the hardest parts of using the strangler fig pattern is maintaining data consistency between the legacy system and new services. During the transition, different parts of the system may own different pieces of data, or changes might need to be reflected in both systems simultaneously.
Techniques like dual writes—where operations write to both systems—or event-driven synchronization through message queues are often necessary. However, these approaches can introduce challenges around eventual consistency, error handling, and transaction management.
Managing Interface Contracts
When legacy and new services coexist, they must agree on the structure and behavior of the data they exchange. Poorly managed interface contracts can lead to brittle integrations, breaking functionality and causing outages.
To mitigate this, teams should use versioned APIs and formal contract testing tools to ensure that changes are safe and compatible. Adopting a consumer-driven contract approach, where downstream services define their expectations, can help catch breaking changes early.
Handling Long Transition Periods
Migrating a large system using the strangler fig pattern can take years. Maintaining momentum over such long periods requires strong technical leadership, clear goals, and stakeholder buy-in.
Teams should break down the migration into small, achievable phases and celebrate progress regularly to maintain morale. Regular reviews of the migration plan, adjusting priorities based on lessons learned, and avoiding scope creep are essential. Importantly, teams should continue delivering business value during the transition.
6 Best Practices for Implementing the Strangler Fig Pattern
Here are some of the ways that organizations can ensure the successful implementation of the strangler fig pattern.
1. Start with Well-Defined Boundaries
The first step toward a successful strangler fig migration is identifying and isolating clear system boundaries. These boundaries define where the legacy system ends and the new functionality begins. Without clear separations, teams risk building tangled integrations that inherit the problems of the old system rather than solving them.
Boundaries can be based on business domains (such as billing, inventory, or customer management), technical subsystems (such as authentication or reporting), or external interfaces (such as APIs or web portals). Domain-driven design (DDD) is a valuable methodology here, helping to identify bounded contexts that naturally segment the system.
Establishing well-defined boundaries allows the new services to be loosely coupled, independently deployable, and easier to manage. It also reduces the risk of regressions by minimizing the surface area where legacy and new components interact. The boundary should be easy to defend and simple so that changes don’t ripple unpredictably across the system.
2. Establish Robust Monitoring and Observability
As the system transitions, visibility into both the legacy and new services becomes mission-critical. Without strong monitoring and observability, it’s impossible to know whether the migration is succeeding or if hidden issues are festering beneath the surface.
Monitoring should cover system performance (response times, throughput, error rates), infrastructure health (CPU, memory, disk usage), and user behavior (clicks, signups, purchases). Observability should also include distributed tracing, allowing teams to follow a request as it travels through both old and new systems.
Setting up centralized logging systems and real-time alerting mechanisms ensures that problems are detected early. Dashboards that visualize key metrics across both environments help maintain operational awareness and support faster incident response.
3. Prioritize High-Impact Components
Not all parts of a system are equally important. Some areas are business-critical, while others are rarely used. Some components have architectural flaws that hamper scalability, while others perform well enough even if they’re outdated. Effective migrations prioritize the components that will deliver the most value if modernized.
Prioritization can be based on business impact (revenue, customer satisfaction), technical risk (fragility, security vulnerabilities), or operational pain points (scalability bottlenecks, maintenance complexity). Starting with high-impact components delivers immediate benefits and builds trust with stakeholders by showing real progress.
It also helps reduce migration fatigue, as the team can point to concrete improvements that matter to the business. When selecting priorities, it’s helpful to use a structured evaluation process—such as scoring each component based on business value, technical risk, and estimated migration effort—to ensure an objective, transparent approach.
4. Ensure Backward Compatibility
During the transition, some users or systems will still depend on the legacy behavior. Breaking these dependencies prematurely can cause outages, lost data, and business disruptions. Backward compatibility ensures that old clients, interfaces, and integrations continue working even as parts of the system are replaced. Techniques to achieve this include:
- API versioning: Keep old and new APIs running in parallel, routing clients to the appropriate version based on request headers or URLs.
- Compatibility layers: Build adapters or translators that convert old data formats or protocols into new ones and vice versa.
- Feature toggles: Introduce new behavior behind feature flags, allowing gradual rollout and fallback if issues occur.
- Schema evolution: Apply additive changes to data schemas (e.g., adding new fields rather than removing or renaming existing ones).
Maintaining backward compatibility often feels tedious, but it’s essential to preserve user trust and system stability while making bold architectural changes under the hood.
5. Modernizing Legacy Web Services With Containers
Containers provide a practical on-ramp for strangling legacy systems without committing to massive rewrites. By containerizing legacy web services, teams can standardize deployments, isolate legacy dependencies, and gain flexibility to run workloads across cloud or on-premise environments.
Containerizing a monolith often involves building a Docker image that wraps the entire application and its runtime environment. This packaging simplifies testing, CI/CD integration, and monitoring. It also decouples the old system from legacy infrastructure, enabling gradual moves to modern orchestration platforms like Kubernetes.
Once in containers, teams can adopt service mesh technologies (like Istio or Linkerd) to add observability, traffic control, and security policies around legacy applications without modifying their code. Further modernization can then happen iteratively: extract small pieces from the monolith into separate containers, introduce sidecars, or rewrite endpoints inside microservices.
6. Document Migration Phases Thoroughly
Long migrations risk losing context, direction, and accountability if not properly documented. Migration work should be treated like any major project, with detailed plans, checkpoints, and records.
For each migration phase, document:
- Objectives: What functionality or system aspect is being migrated? What are the success criteria?
- Scope: What is included, and what is explicitly out of scope for this phase?
- Dependencies: What other systems, teams, or technologies does this phase rely on?
- Risk analysis: What are the main risks, and how will they be mitigated?
- Rollback plan: If the migration phase fails, how will the system be restored to its previous state?
- Timeline: Clear milestones and deadlines for completion.
Updating architectural diagrams and decision records after each phase ensures the team—and future teams—understand how the system evolved. Good documentation also supports audits, compliance efforts, and post-mortem reviews.
Automating Legacy Software Modernization with Swimm
Swimm’s Application Understanding Platform helps solve one of the biggest challenges in modernization – the lack of understanding of existing applications. Swimm is able to be deployed in highly secure environments and uses deterministic static analysis and generative AI to produce proven, reliable and cost-effective insights.
Key features include:
- Business rule extraction: Accurately extracts all the business rules and logic in the codebase.
- Architectural overviews: Finds and explains the component architecture of the application and breaks down programs, jobs, flows and dependencies.
- Natural language: Turns vague program and variable names into descriptive names for quickly understanding connections and flows.
- Customizable support: Supports complex and proprietary implementations of COBOL, CICS, and PL/I through language parsers and company specific plug-ins.