Architecture patterns
Strangler fig migration
How to move from a monolith to services one capability at a time, with a router in front, and why "monolith first" is the default advice.
If you have a monolith and good reasons to extract services, don't rewrite it. Martin Fowler named the strangler fig pattern after vines that grow around a host tree until they replace it. You put a router in front of the monolith, move one capability at a time into a new service, and send that capability's traffic to the new service. The old system shrinks until it is gone, or small.
The big idea
Each step is small, reversible and delivers value on its own. A big-bang rewrite delivers nothing for years and often fails at launch. The strangler approach lets you stop at any point with a working system.
Walking through it
Say you extract invoices from a monolith. The router sends invoice traffic to the new service and everything else to the monolith:
Router rules:
/invoices/* -> invoices service (new)
everything else -> monolith (unchanged)
GET /invoices/77 -> router -> invoices service
GET /cart -> router -> monolithThe steps repeat for each capability:
- Put a routing layer, such as a proxy or API gateway, in front of the monolith.
- Build one new capability, or extract one existing one, as a service.
- Route that capability's traffic to the new service. Everything else still goes to the monolith.
- Repeat, one capability at a time.
The data is usually the hardest part. The new service needs its own copy of its data. Migrate it with dual writes, or with change data capture while both systems run. Then cut over, and stop the monolith from writing that data.
When to split at all
For new systems, Fowler's MonolithFirst advice is the mainstream view. Almost every successful microservice system began as a monolith that grew too big. Many systems built as microservices from scratch ran into trouble, because the right boundaries aren't visible until the domain has been explored.
Start with a well-structured modular monolith. Extract a service when a specific pressure demands it:
- A team needs to deploy independently.
- One component has very different scaling or reliability needs.
- A security boundary needs enforcing.
Common mistakes
- Rewriting from scratch. Big-bang rewrites delay value and concentrate risk on launch day.
- Moving the code but not the data. The service still depends on the monolith's tables, so it hasn't really been extracted.
- Extracting before the boundaries are clear. Boundaries become network APIs, so a wrong guess is expensive to fix.
Check yourself
-
What does the router do during the migration?
It sends each capability's traffic to either the new service or the monolith, so both run side by side while the move happens.
-
Why is "monolith first" the default advice?
Successful microservice systems usually began as monoliths, and the right boundaries are hard to see before the domain is understood.
Key takeaways
- Move one capability at a time behind a router, so every step is small and reversible.
- Data moves with the service, using dual writes or change data capture before cutover.
- Start with a modular monolith, and extract services only under a specific pressure.
Further learning
Martin Fowler's MonolithFirst article explains why most successful systems start as monoliths.
MonolithFirst (Martin Fowler)Monolith Firstmartinfowler.comReturn to the microservices overview to see how these pages fit together.
Related
Monoliths and microservices
When to split a system, how to draw service boundaries, and the operational cost that microservices add.
Event-driven architecture, CQRS and event sourcing
Building systems around events, from change data capture to event sourcing and read models, and knowing when it simplifies a system versus creating a distributed mess.
API design
An API is a contract that outlives the code behind it. Design the styles, methods, pagination, errors and async flows so changes stay additive.