← ALL INSIGHTS
INSIGHT · 6 MIN READ

Legacy Modernisation: A Safer Strangler Fig Migration Plan.

strangler fig
  • Legacy modernization is safest when you replace one business capability at a time, not the whole system at once.
  • The strangler fig pattern places a routing layer in front of the old system so new code can take over gradually.
  • Trust comes from evidence. Compare old and new behavior on real traffic before you move customers.
  • The migration is only finished when the old path is deleted.

Most legacy modernisation programs do not fail because the new technology is bad. They fail because the plan asks the business to trust one big switch that nobody can test. Incremental legacy modernisation removes that bet. You move one business capability, prove it works, and only then move the next.

This guide uses a hypothetical account-notification service to explain boundaries, coexistence, traffic routing, behaviour comparison and the retirement of the old path. You can try a routing simulator and a readiness checklist as you read.

What is the strangler fig pattern?

The strangler fig pattern is a legacy system migration strategy in which you build new functionality around the edges of an old system and gradually route work to it, until the old system can be switched off. Martin Fowler popularized the name. It comes from strangler figs, vines that grow around a host tree and slowly replace it.

In practice, the strangler fig pattern for microservices teams is simple. Put a facade or proxy in front of the legacy application. Carve out one capability and rebuild it as a new service. Let the facade decide, request by request, which path answers.

Why incremental beats a big bang rewrite

A full rewrite delivers nothing until it delivers everything. Meanwhile the old system keeps changing, so the target keeps moving. Incremental legacy application modernization strategies avoid that trap.

Big bang rewriteIncremental (strangler fig)
RiskConcentrated in one cutoverSpread across small, reversible steps
FeedbackArrives at the endArrives with every capability
RollbackHard or impossibleA routing change
Business valueDelayed until launchDelivered capability by capability

Our example: a hypothetical account-notification service

Imagine an enterprise platform built around a twenty-year-old monolith. Inside it sits an account-notification module. It sends emails and texts when a password changes, a new device signs in or a payment fails. Other modules call it directly, it reads customer data from the shared database, and nobody remembers every rule it applies.

This example is invented, but the shape is common. Notifications make a good first capability: they are visible and valuable, and a mistake has a smaller blast radius than it would in billing or identity.

Step 1: Draw the boundary

Define the capability by the business outcome it owns. Here that outcome is: tell the customer when something important happens to their account. Everything the capability needs to deliver that outcome belongs inside the boundary.

Inventory the real behavior

List the inputs (account events), the outputs (messages and delivery status) and the data owned (templates, preferences, send log). Then look for the quiet rules: quiet hours, duplicate suppression, regional legal footers. Document the contract the old module actually follows, not the one in the wiki.

Find the hidden couplings

Search for every caller and every table the module touches. Direct method calls and shared tables are the usual surprises. Each one is a seam you will need to replace with an event or an API.

Step 2: Let old and new coexist

For a long time, both paths will be alive. Design for that on purpose, because coexistence is where most migration incidents happen.

Put a routing layer in front

Add a facade, gateway or proxy that receives every notification request. At first it forwards everything to the old module. The old path stays the default, and the new service earns each increment of traffic.

Decide who owns the data

Avoid two writers for the same data. Prefer a single source of truth and let the new service consume events instead of reading the old tables. If you must synchronize, make the direction explicit and monitor for drift.

Step 3: Route traffic gradually

Traffic routing is where the strangler fig pattern becomes real. You do not flip a switch. You move a controlled share of requests, watch what happens, and move the dial again. Drag the slider to see how each stage changes.

Try it: split traffic between old and new

Share of live requests handled by the new service: 0%

Old: 1000 per 1,000New: 0 per 1,000

Shadow mode. The old path answers every request. The new service gets a copy, and you compare its output without sending anything to customers.

Step 4: Compare behavior before you trust it

Shadow mode is the safest way to start. The old path still answers every request. The new service receives a copy, and you record what it would have done without sending it to a customer.

For notifications, compare the template chosen, the recipient, the channel, the timing and the suppression decision. Sort every difference into one of three groups: a bug in the new service, a bug in the old one (decide whether to preserve or fix it), or an acceptable difference.

Write the exit criteria before you start. For example: no unexplained differences across a full business cycle, including month-end and billing runs. Evidence beats confidence, and a written threshold keeps the decision honest.

Step 5: Retire the old path

A migration that leaves the old path alive creates a second system to maintain. Set a retirement date at the start, and treat the end of the project as deletion, not cutover.

Remove the routing rule and the feature flags. Delete the old module, its scheduled jobs and its unused tables. Update runbooks and dashboards, archive the logs you must keep, and confirm that no caller still depends on the old interface. Then pick the next capability and repeat.

Check your readiness

Tick what is true for your team today.

Is your first capability ready to migrate?

We can name the business outcome this capability owns.

We have listed every caller and every shared data store.

A routing layer can split traffic by request or customer segment.

We can return to the old path in minutes.

We wrote exit criteria for comparing old and new behavior.

A named owner and a date exist for retiring the old path.

0 of 6 ready. Not yet. Close the gaps above before you route any live traffic.

Common mistakes to avoid

  • Starting with the hardest capability instead of a valuable, contained one.
  • Sharing the legacy database indefinitely.
  • Skipping comparison because the new code seems obviously better.
  • Leaving the retirement date undefined.
  • Treating modernization as an IT-only project, without business owners.

Frequently asked questions

What is legacy modernization?

Legacy modernization is the process of updating or replacing older software so it is easier to change, run and secure, while the business keeps operating. Approaches range from rehosting to full replacement.

What is the strangler fig pattern in microservices?

It is an approach where a routing layer sits in front of a legacy application and sends selected requests to new microservices. Over time the new services handle more work until the old system is removed.

How long does incremental legacy modernization take?

There is no honest universal number. Each capability takes as long as its size and coupling require, and the program continues until every capability is moved. The benefit is that value arrives with each slice instead of at the end.

What is the best legacy system migration strategy?

For systems that must keep running, an incremental strategy such as the strangler fig pattern is usually the safest. A full rewrite can make sense only for small, well-understood systems.

When should you avoid the strangler fig pattern?

Avoid it when you cannot intercept requests at any boundary, or when the system is small enough to replace safely in one step.

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.