Stop Doing "Big Bang" Rewrites: Master the Strangler Fig Pattern
This is two parts series, here is the part - 1, you can refer the part 2 here, I would suggest reading sequentially.
If you’ve been in software engineering long enough, you’ve likely heard a developer say, "This legacy codebase is a mess. We just need to stop feature work for six months and rewrite it from scratch."
This is the "Big Bang" rewrite. And historically, it is one of the riskiest maneuvers a software team can attempt.
To safely modernize legacy systems, we need a better approach. Enter the Strangler Fig Pattern, a concept coined by Martin Fowler (and heavily associated with Thoughtworks) that allows teams to incrementally migrate a legacy system without halting business value.
Here is a breakdown of how it works, the architectural mechanics behind it, and when you should (and shouldn't) use it.
Why Big-Bang Rewrites Fail
The naive approach to modernizing a legacy monolith is to freeze the old system, build a complete replacement in a vacuum, and then cut over all at once. This usually ends in disaster for a few reasons:
- The Parallel Maintenance Trap: Rewrites take time—often years. During this time, the old system still needs bug fixes and security patches. You end up maintaining two systems in parallel with zero incremental payoff.
- Maximum Risk on Day One: The new system inevitably has edge-case bugs that only surface under full production load. "Day one" of the cutover becomes the highest-risk moment of the entire project.
- Moving Targets: Business requirements keep changing while you rewrite. By the time the "final" target is finished, it is already outdated.
- The Second-System Effect: As Fred Brooks noted in The Mythical Man-Month, teams tend to over-engineer the replacement. Because they have a blank slate, they try to fix every architectural complaint about the old system at once, severely bloating the scope.
What is the Strangler Fig Pattern?
In software, it means putting a facade in front of your legacy system and gradually replacing functionality piece by piece until the legacy system can be safely decommissioned.
How it Works (Step-by-Step)
- Deploy a Facade: Place an API Gateway or reverse proxy in front of the legacy system. Initially, it routes 100% of incoming traffic to the old system. The user experience remains completely unchanged.
- Pick a Slice: Choose one small piece of functionality—like a specific endpoint or a distinct business capability (e.g., "Order History").
- Build and Route: Build that single piece in the new architecture. Update the facade to route traffic for only that specific capability to the new system, while everything else falls back to the legacy monolith.
- Verify: Test the new slice in production. Teams often use shadow traffic (sending a copy of real traffic to the new system silently to compare outputs) or canary releases before fully committing.
- Rinse and Repeat: Pick the next piece. Build, reroute, verify. Do this until the facade routes 100% of traffic to the new microservices.
- Decommission: Turn off the legacy monolith.
The core benefit: At every single step, your system is in a fully working, shippable state. You are never stuck in a "half-built, nothing works" limbo.
The Architectural Mechanics
How do you actually build this? There are two main technical challenges you have to solve: routing and data synchronization.
1. The Facade Layer (Routing)
This is usually an API Gateway, an AWS Application Load Balancer (ALB), or a reverse proxy like NGINX using path-based routing.
Here is what that looks like in a basic NGINX configuration:
server {
listen 80;
server_name api.myapp.com;
# 1. The "Strangled" Piece: Route to the new microservice
location /api/v2/orders {
proxy_pass http://new-orders-microservice:8080;
}
# 2. The Fallback: Everything else goes to the legacy monolith
location / {
proxy_pass http://legacy-monolith:80;
}
}
2. The Data Synchronization Challenge
Routing web requests is the easy part. The hard part is state.
If the legacy system and the new system both need access to the same underlying data during the multi-month transition, they need to stay in sync. There are two common ways to handle this:
- Dual Writes: The application layer is configured to temporarily write data to both the old database and the new database.
- Change Data Capture (CDC): A much more robust approach. You stream database changes from the legacy system's database into the new system in near-real-time. Tools like Debezium (often paired with Kafka) are industry standards for this. It allows the new system to have its own pristine data model while staying seamlessly updated without touching the legacy code.
Where Do You Start?
When deciding which piece of the monolith to strangle first, you generally have two choices:
- Lowest Risk, Highest Confidence: Pick a simple, read-only feature first. This proves the routing infrastructure works, builds developer confidence, and earns trust from stakeholders without risking critical business flows.
- Highest Active Pain: Pick the part of the monolith that fails the most, scales the worst, or requires the most active feature development. This delivers massive business value upfront, though it carries higher technical risk.
Pro tip: Start with one low-risk component to test the pipes, then immediately target a high-pain component.
When to Use (and When to Avoid) Strangler Fig
✅ When it's the right call:
- The system is business-critical. You cannot afford extended downtime or a highly risky cutover.
- The system is massive. A full rewrite would genuinely take months or years.
- The business cannot freeze feature development. You need to keep shipping value while the migration happens in the background.
❌ When it's overkill:
- The system is small enough that a team could completely rewrite and test it in a few weeks.
- The system isn't mission-critical.
- Why? Strangler Fig introduces complex, temporary infrastructure (the facade, dual-routing, CDC pipelines). If a careful rewrite-and-cutover is genuinely feasible, don't take on the overhead of maintaining two systems at once.
Conclusion
Modernizing a legacy system isn't just a technical challenge; it's a risk management exercise. By using the Strangler Fig pattern, you trade the heart-stopping panic of a midnight Big Bang cutover for a series of boring, predictable, incremental deployments. And in software engineering, boring is exactly what we want.

Top comments (0)