The Monolith Is Not Dead: When Microservices Are the Wrong Choice
The Microservices Hangover
Between 2015 and 2020, the industry collectively decided that monoliths were legacy and microservices were the future. Companies with 10 engineers and 5 services wondered why everything felt so hard.
The answer is simple: microservices trade development complexity for operational complexity. If your operational burden was not your bottleneck, you made the wrong trade.
What Microservices Actually Solve
Microservices are an organizational pattern, not a technical one. They solve the problem of independent deployment at team scale:
- 50+ engineers who cannot all work in the same codebase without constant conflicts
- Different scaling requirements — your search service gets 100x the traffic of your billing service
- Different technology requirements — your ML pipeline needs Python while your API is in Go
- Regulatory boundaries — PCI compliance for payments, HIPAA for health data
If you do not have these problems, you do not need microservices.
The Modular Monolith
The alternative is not a tangled ball of spaghetti code. A well-structured monolith has clear module boundaries, explicit interfaces between components, and separation of concerns — without the network calls, serialization overhead, and distributed systems debugging.
Rails, Django, and Laravel applications have been doing this for decades. The pattern works. The key is disciplined module boundaries:
- Each module owns its database tables
- Modules communicate through defined interfaces, not shared state
- You can extract a module into a service later if you need to
The Pragmatic Path
Start with a monolith. Add strict module boundaries. Monitor where the bottlenecks actually are. Extract services only where you have proven the need. This is not settling — it is engineering.