You have a 10-year-old monolith. How would you start the migration into microservices architecture?
Target Architecture

If you’re presenting this to architects or engineering leadership, it’s often easier to show the migration as a sequence of deployment diagrams rather than jumping directly to the target state.

Stage 0 – Current State (Monolith)
Everything deployed together.
Users
|
Load Balancer
|
+------------------+
| Monolith |
|------------------|
| Auth |
| Customer |
| Product |
| Order |
| Payment |
| Notification |
+------------------+
|
Shared Database
Deployment:
Monolith v1.0
└── Single deployment artifact
Problem:
- Every release deploys everything
- Scaling entire application
- Long regression testing
Stage 1 – Introduce API Gateway
No functionality changes.
Users
|
API Gateway
|
+----------------+
| Monolith |
+----------------+
|
Shared Database
Benefits:
- Single entry point
- Routing abstraction
- Foundation for Strangler Pattern
Stage 2 – Extract Notification Service
Notification is usually low risk.
New Deployment
Users
|
API Gateway
|
+----------+----------+
| |
Monolith Notification Service
|
Shared Database
Glue Code Inside Monolith
Before:
notificationService.sendEmail()
After:
notificationFacade.sendEmail()
Glue Code:
if(featureFlag.notificationEnabled()){
notificationClient.sendEmail();
}else{
oldNotificationService.sendEmail();
}
Canary Deployment
Deploy Notification Service separately.
Traffic:
Email Requests
95% -> Monolith Notification
5% -> Notification Service
Monitor:
- Error rate
- Latency
- Delivery success
Then:
95/5
80/20
50/50
0/100
Stage 3 – Notification Fully Migrated
Users
|
API Gateway
|
+----------+----------+
| |
Monolith Notification Service
|
Shared Database
Monolith now calls:
Notification API
instead of local code.
Stage 4 – Extract Product Service
Next candidate:
- Moderate complexity
- Mostly CRUD
- Clear boundaries
Architecture
Users
|
API Gateway
|
+----------------+------------------+
| | |
Monolith Product Service Notification
Service
Temporary Database Strategy
Initially:
Product Service
|
+-------> Shared Database
Not ideal but practical for migration.
Glue Code
Inside Monolith:
productFacade.getProduct(id)
Facade:
if(featureFlag.productServiceEnabled()){
return productClient.getProduct(id);
}
return monolithProductModule.getProduct(id);
Canary
Product Requests
95% -> Monolith
5% -> Product Service
Then:
95/5
80/20
50/50
100%
Stage 5 – Product Owns Database
Now move ownership.
Product Service
|
Product DB
Synchronize data:
Monolith Product Module
|
v
Product DB
Temporary synchronization layer.
Stage 6 – Extract Customer Service
Architecture becomes:
Users
|
API Gateway
|
+----------+------------+------------+-------------+
| | | | |
Monolith Product Customer Notification
Service Service Service
Glue Code Layer
Inside Monolith:
CustomerFacade
ProductFacade
NotificationFacade
These facades hide migration complexity.
Stage 7 – Event-Based Integration
Current state:
Monolith
|
Product Service
|
Customer Service
Many synchronous calls.
Move to events.
Event Bus
|
+------------------+-------------------+
| | |
Product Service Customer Service Notification
Examples:
CustomerCreated
ProductUpdated
OrderCreated
Stage 8 – Extract Order Service
Now business-critical domain.
Architecture:
Users
|
API Gateway
|
+----------+------------+------------+-------------+
| | | | |
Monolith Product Customer Order Notification
Service Service Service Service
Canary for Order Service
Never move all orders immediately.
Order Creation
99% -> Monolith
1% -> Order Service
Then:
99%
95%
80%
50%
20%
0%
Rollback instantly if needed.
Stage 9 – Extract Payment Service
Most risky service.
Architecture:
Users
|
API Gateway
|
+--------+---------+---------+---------+---------+
| | | | | |
Monolith Product Customer Order Payment Notification
Service Service Service Service Service
Canary:
Payment Requests
99.5% -> Monolith
0.5% -> Payment Service
Increase very slowly.
Stage 10 – Monolith Shrinks
Only remaining modules:
Monolith
├── Legacy Reporting
├── Legacy Admin
└── Remaining Features
Everything else moved.
Final State
Users
|
API Gateway
|
+-----------+------------+------------+------------+
| | | | |
Product Customer Order Payment Notification
Service Service Service Service Service
| | | | |
Product DB Customer DB Order DB Payment DB Notify DB
|
Event Bus
|
Reporting Service
Where Glue Code Exists During Migration
Monolith
├── ProductFacade
├── CustomerFacade
├── OrderFacade
├── PaymentFacade
└── NotificationFacade
Each facade:
Feature Flag OFF
|
v
Old Monolith Logic
Feature Flag ON
|
v
Microservice Call
After migration:
Delete Facade
Delete Old Code
Delete Feature Flag
Recommended Canary Progression
| Service | Initial Canary |
|---|---|
| Notification | 5% |
| Product | 5% |
| Customer | 5% |
| Order | 1% |
| Payment | 0.5% |
Traffic progression:
0.5%
1%
5%
10%
25%
50%
75%
100%
This gives you a true Strangler Pattern migration, where the monolith continuously shrinks, glue code bridges old and new worlds, and every service is introduced through canary deployments rather than a risky big-bang release.