Skip to main content
theordinarycompany
🌿Engineering
EngineeringUpdated: 11 min read

Strangler Fig Pattern: Safely Modernize Legacy Systems

Learn the strangler fig pattern for legacy modernization. A step-by-step guide to incrementally replacing old systems without risky big-bang rewrites.

What Is It?

The strangler fig pattern is named after tropical fig trees that wrap around host trees, eventually replacing them entirely while the host continues to live.

In software, it means building a new system around your old one, gradually migrating traffic until the old system can be safely removed.

It's the opposite of the "big bang rewrite"—where you build a completely new system and switch over all at once. Big bang rewrites fail constantly. The strangler pattern almost always succeeds.

Big bang rewriteStrangler pattern
All or nothingIncremental progress
Value delivered at the endValue delivered throughout
One chance to get it rightMany chances to course-correct
Team burns outTeam builds momentum

When to Use It

The strangler pattern works best when:

  • Your legacy system still runs and serves traffic
  • You can put a routing layer in front of it
  • You have time (months, not days)
  • Business continuity is critical

It doesn't work well when:

  • The system is so broken it can't run reliably
  • You can't intercept requests
  • The codebase is too small to justify the overhead
  • Everything needs to change at once

For most legacy modernization projects, the strangler pattern is the right choice. We've used it successfully on systems ranging from 10-year-old PHP monoliths to enterprise Java applications.


How It Works

Step 1: Add a routing layer

Put something in front of your legacy system that can direct traffic. This could be an API gateway, a load balancer, or even just nginx.

At first, everything goes to the old system. The routing layer is just passing through.

Step 2: Identify the first slice

Pick a piece of functionality to modernize. Good first candidates:

  • High business value but low complexity
  • Well-defined boundaries
  • Not tightly coupled to everything else

Authentication is often a good starting point. So is reporting/analytics.

Bad first candidates:

  • The "core" of the system
  • Anything touching payments until you're confident
  • Components with unclear boundaries

Step 3: Build and shadow

Build the new version of that component. Don't route real traffic to it yet—instead, run it in parallel and compare results.

Send requests to both systems. Log any differences. This catches bugs before users see them.

Step 4: Gradually shift traffic

Start with 1% of traffic. Then 5%. Then 25%. Watch your metrics at each stage.

If something breaks, shift back to 0%. Fix it. Try again.

Step 5: Decommission the old component

Once 100% of traffic is on the new system and you're confident, remove the old code.

Step 6: Repeat

Pick the next slice. Do it again. Each iteration gets easier as your team learns and the remaining legacy surface shrinks.


A Real Example

A client came to us with a 15-year-old PHP system handling €2M/month in transactions. They'd tried two rewrites before—both failed.

Month 1: Routing layer + authentication

We added an API gateway and rebuilt user authentication as a separate service. Low risk, high visibility—everyone logs in, so quick wins show up immediately.

Month 2: Product search

The old search was painfully slow. We built a new service using Elasticsearch. Shadow-tested for a week, caught three edge cases, then rolled out.

Users noticed. Support tickets about "slow search" dropped to zero.

Month 3-4: Order processing

The scary part. We built the new order service but shadow-tested for almost three weeks before shifting any real traffic.

For two weeks, both systems processed orders and we compared every single transaction. When we found discrepancies (we found four), we fixed them before anyone was affected.

Month 5-6: Everything else

By this point, the remaining legacy code was mostly admin tools and reporting. Less critical, easier to migrate.

Final result:

The whole process took 6 months. At no point did the business stop operating. At no point did we have to tell customers "sorry, we're migrating."

Compare that to the two previous rewrite attempts—18 months each, neither shipped.


Common Mistakes

Moving too fast. The whole point is incremental progress. If you're trying to strangle half the system in the first month, you've just turned it into a big bang rewrite with extra steps.

Ignoring data migration. Two systems mean data in two places. You need a clear strategy for keeping data in sync during the transition.

Underinvesting in the routing layer. If your routing logic is fragile, everything is fragile. Make it robust, make it observable.

Skipping shadow testing. Yes, it takes extra time. Yes, it's worth it. The bugs you catch in shadow mode would have been production incidents.

Declaring victory too early. Don't remove old code until you're certain the new system handles all the edge cases. "It works in testing" isn't good enough.


Is it right for your project?

If you're struggling with a legacy system and a full rewrite feels too risky, the strangler pattern is probably your answer.

We've used it on dozens of projects. Happy to walk you through how it might apply to your specific situation.

📬 Get Engineering Insights

Practical articles on MVP development, legacy modernization, and building products that scale. Delivered to your inbox.

No spam. Unsubscribe anytime. We respect your privacy.

TOC

The Ordinary Company

Product-minded engineers helping startups build and scale. 50+ projects delivered.

🚀

Ready to Build Your Project?

Let's discuss how we can help bring your ideas to life. Free consultation, no strings attached.