← ALL INSIGHTS
INSIGHT · 7 MIN READ

Strangler Fig Pattern: Modernize One Business Capability at a Time.

strangler fig

A safer migration plan for CTOs and platform leads, walked through with a hypothetical account-notification service. It is an incremental legacy modernization approach. You build a new implementation of one business capability beside the old one, route traffic to it in controlled steps, compare behavior against the legacy path, and retire the old path only after the new one is proven.

Why incremental legacy modernization beats the big-bang rewrite

Most enterprises carry at least one system that nobody wants to touch and nobody can replace overnight. It runs billing, orders or notifications, and it works well enough that the business depends on it.

A full rewrite looks tidy on a slide. In practice it hides risk until the cut-over date, when every undocumented behavior surfaces at once.

Martin Fowler described the alternative in 2004 after seeing strangler figs in the rainforests of Queensland. His suggestion was to “gradually create a new system around the edges of the old.” He also named the main reason to prefer this route over a cut-over rewrite: reduced risk. He noted that rewrites are always more complex than they look, because even old bugs often have to be carried across.

That is the heart of a sound legacy modernization strategy. You shrink the unit of change until each step is small enough to reverse.

What is the strangler fig pattern in three moves?

The pattern has three moves that repeat for every capability:

Transform: build the new implementation of one capability.
Coexist: run old and new together behind a routing layer.
Eliminate: remove the old path once the new one has earned trust.

The rest of this article applies those moves to one concrete case, so you can reuse the plan for your own legacy system migration strategy.

The example: a hypothetical account-notification service

Picture a financial platform whose monolith sends account notifications: password resets, failed-payment alerts, low-balance warnings and “statement ready” messages. Email, SMS and push logic all live inside the monolith and read shared database tables.

This is a hypothetical scenario built for illustration. It does not describe a specific client, and the numbers you choose will depend on your own systems and risk appetite.

Notifications make a good first capability. They are customer-visible, so mistakes get noticed. They are also event-driven, so inputs and outputs are easy to observe and compare. That balance is what you want in a first slice.

Step 1: Draw the boundary and build the seam

Define the capability in one sentence

Write it down: given an account event, decide who is notified, on which channel and with what content, then record the outcome. Everything inside that sentence moves. Everything outside it stays.

For our example, authentication and customer profile ownership stay in the monolith. The new service reads preferences through an API instead of reaching into shared tables.

Write the contract before the code

Agree on three things with the teams that depend on you:

Input: an account event with a unique event ID.
Output: a message request plus a delivery record.
Guarantee: the same event ID never produces two sends.

Add a routing seam first

Put a facade, API gateway or event router in front of the notification calls. At the start it sends 100 percent of traffic to the legacy path. This changes no behavior, but it gives you the control point every later step depends on.

Step 2: Plan coexistence, because both systems will run for a while

Coexistence is where most migrations get hurt, so give it real design time.

One system of record per data set. At any moment, exactly one side owns notification preferences. Avoid dual writes. Publish changes through an event stream or an outbox table so the other side follows.

Idempotency everywhere. If both paths can see the same event, a customer could get two texts. A shared event ID and a send ledger prevent that.

Shadow before live. In shadow mode, the new service receives a copy of each event and decides what it would send, but sends nothing. You get production-shaped data with zero customer impact.

Step 3: Route traffic with a canary deployment strategy

A canary deployment strategy moves traffic to the new path in small, observable steps. For a capability migration, route by account cohort, not by random request. A customer should not get half their alerts from one system and half from the other.

Use the simulator below. Drag the slider through an illustrative rollout and see what to check at each stage.

Traffic routing simulator

ShadowInternalSmallLargerHalfFull

Shadow mode · 0% live

What to check: The new service gets copies of events and computes decisions. Nothing is sent. Compare every decision with the legacy result.

Canary deployment vs blue green

Teams often ask about canary deployment vs blue green. They solve different problems, and a migration usually uses both.

CanaryBlue green
How it shifts trafficGradually, by cohortAll at once, between two full environments
RollbackReduce the routed shareSwitch back to the old environment
Exposure if wrongLimited to the canary cohortEveryone, until you switch back
Best use hereMoving a capability from legacy to newReleasing new versions of the new service

Step 4: Compare behavior before you trust it

Passing tests does not prove the new path matches production. Comparing real decisions does.

For every event in shadow mode, store what the legacy path decided and what the new service would decide. Compare meaningful fields, not raw bytes: recipient, channel, template, and timing.

Then sort each mismatch into one of three buckets:

New service bug: fix it.
Legacy bug customers rely on: decide on purpose whether to copy it or change it, and tell the business.
Acceptable difference: document it and move on.

Agree on pass criteria with the capability owners before the rollout starts. Useful signals include match rate, delivery latency, failure rate, duplicate sends and support contacts. Choosing thresholds in advance stops the team from moving the goalposts under deadline pressure.

Step 5: Retire the old path on purpose

Old code that stays “just in case” keeps costing you. It still needs patches, infrastructure and on-call knowledge, and it quietly keeps the old risk alive.

Keep the legacy path warm while the new one runs at full traffic through at least one complete business cycle, such as a statement run. Then work through the list below.

Retirement checklist

New path has carried 100% of traffic through a full business cycle

Behavior comparison shows no unexplained mismatches

Changes to the legacy notification code are frozen

Rollback window has ended and the owner has signed off

Routing fallback to the legacy path is removed

Historical data is archived or migrated

Legacy code, jobs and infrastructure are deleted

Runbooks, dashboards and alerts point only to the new service

0 of 8 complete

Common legacy modernization challenges, and how to handle them

Shared databases. Replace direct table access with an API or events before moving logic.

Scope creep. The new service should match old behavior first. Improvements come after the cut-over.

Parallel-run fatigue. Set an end date for coexistence at the start. Open-ended dual running drains teams.

Undocumented behavior. Shadow comparison finds it. Interviews rarely do.

No clear owner. Name one accountable owner per capability, with authority to approve each routing step.

Choosing your next capability

Pick slices that are well bounded, observable, and low enough in blast radius to teach the team. Notifications, document generation and reporting often qualify. Core ledgers and pricing engines usually come later, once the routing, comparison and retirement habits are proven.

A good application modernization program is a series of small, boring, reversible wins. That is the point.

Frequently asked questions

What is the strangler fig pattern?

It is an incremental way to replace a legacy system. You build new functionality beside the old, route traffic gradually, and remove the old code once it is no longer used.

How long does incremental legacy modernization take?

It depends on how many capabilities you move and how tangled their data is. Plan in slices, and judge progress by capabilities retired, not by calendar dates.

When should you not use the strangler fig pattern?

Skip it when the system is small enough to rewrite safely, or when no clean seam exists to route traffic through. In the second case, create the seam first.

Should we use canary or blue green deployment?

Use canary routing to move a capability from legacy to new. Use blue green when releasing versions of the new service itself.

What is a good first capability?

One with clear inputs and outputs, an accountable owner, and observable results. Notification services are a common choice.

THE CONVICTION BRIEF

One brief like this, monthly.

Subscribe
FAQ

On modernizing CPG data

What does "data as a product, not a byproduct" actually mean?

It means each critical data domain gets a named owner accountable for its quality, availability, and adoption. A byproduct has no owner, no roadmap, and no service level; a product is measured by whether people use it. The shift is organizational before it is architectural.

Why start with the organization instead of the technology?

The three shifts in this piece are ownership, consumption, and governance — and none is primarily a technology decision. Companies that dominate with data made the decision before they drew the diagram. New tooling on top of unowned data just moves the same problem to a faster stack.

What's wrong with a 2015-era data stack?

Those stacks were optimized for storage and ingestion — getting data in and keeping it. Modern stacks optimize for the person pulling data out: the demand planner, the trade manager, the pricing agent. The stack that wins is the one the business actually pulls from, not the one that stores the most.

How is governance-as-enabler different from governance theater?

Governance that lives in review boards slows everything and protects little. Governance that lives in the platform — contracts, permissions, and quality gates enforced at the pipeline — speeds teams up and holds under audit. One is a meeting; the other is enforced by default.

Do we need to rebuild everything at once?

No. Start by assigning an owner to one critical domain and designing that domain for consumption, then move governance into the platform for it. The pattern is deliberate and incremental, which is why the leaders treat it as a series of shifts rather than a single migration.