The microservices vs monoliths debate has been raging for years. After working on both architectures in production at scale, we have developed a nuanced perspective that most blog posts miss.
When Monoliths Win
For teams of fewer than 15 developers with a single business domain, a well-structured monolith is almost always the right choice. Laravel's modular structure with actions, services, and domain-driven design keeps the codebase clean.
// Modular monolith structure in Laravel
app/
Modules/
Billing/
Actions/
Models/
Services/
Inventory/
Actions/
Models/
Services/
When Microservices Shine
Microservices become valuable when you have multiple teams working independently, different scaling requirements for subsystems, or polyglot persistence needs.
The Service Mesh Trap
Many teams adopt service meshes, distributed tracing, event sourcing, and CQRS before they need them. This adds enormous complexity with little benefit for most applications.
"Start with a monolith. Extract microservices when you can feel the pain of the monolith — not when you anticipate it."
Our Production Experience
We built a platform as a monolith, extracted three services (billing, notifications, reporting), and kept the core as a modular monolith. This hybrid approach gave us the best of both worlds.
- Shared Kernel: Common domain logic stays in the monolith
- Bounded Contexts: Clear module boundaries with well-defined interfaces
- Event-Driven Integration: Laravel broadcasting for cross-module communication
Key Takeaway
Architecture should be boring. Choose the simplest solution that meets your current needs and refactor when the cost of complexity exceeds the cost of change.