The Strangler Fig Pattern replaces a legacy system in stages. A boundary intercepts requests, events, or workflows and directs each one to either the old implementation or a new component. The legacy system keeps handling capabilities that have not moved. Its scope contracts as the new system takes over.
How the pattern works
The pattern requires a place where traffic can be divided. For a web application, that point may be a proxy or gateway. For internal processing, it may be an event router, a service interface, or a workflow boundary. The routing rule must identify which implementation owns each capability during the transition.
| Stage | Legacy system | New system | Routing boundary |
|---|---|---|---|
| Establish | Handles all live behaviour | Exists beside it | Observes or forwards traffic |
| Migrate | Keeps unmoved capabilities | Handles selected capabilities | Splits traffic by explicit rule |
| Validate | Remains available where needed | Becomes the owner of moved work | Supports comparison or rollback |
| Retire | Has no remaining responsibility | Handles the full chosen scope | Is simplified or removed |
The stages can repeat for each business capability. Retirement happens only after callers, data paths, operational jobs, and fallback procedures no longer depend on the old implementation.
What an audit must establish first
A legacy codebase audit identifies boundaries that the system can actually support. A screen or source-code module is not automatically a migration unit. The capability may share database tables, scheduled work, authentication state, or transaction rules with other parts of the application.
The audit therefore traces:
- Entry points. Requests, events, files, and jobs that begin the behaviour.
- State ownership. The system that reads and writes each relevant record.
- Downstream effects. Calls, messages, reports, and notifications produced by the flow.
- Retirement conditions. Dependencies that must disappear before old code can be removed.
Managing coexistence
During a staged migration, old and new components operate at the same time. An Anti-Corruption Layer can translate between their data models and vocabulary when direct integration would pull legacy assumptions into the new design. Refactoring may also be needed to expose a stable routing point where none exists.
Coexistence adds operational work. Monitoring must show which path handled a request. Data synchronisation needs an explicit direction and owner. Failure handling must state whether traffic returns to the legacy path, stops, or is retried. These are properties of the transition architecture, not details to decide after deployment.
How it shapes a migration plan
The pattern turns one replacement project into a sequence of capability moves. Each move has a defined entry point, data scope, verification method, and retirement condition. This makes progress visible in terms of responsibilities removed from the old system.
It does not remove the need to understand the codebase. It depends on that understanding to choose boundaries that can coexist and later separate. The value of planning a legacy migration this way is that each completed stage can run in production before the next part moves, while the final goal remains the removal of obsolete code and dependencies.