Microservices vs Monolith
Monoliths are simpler to build and operate; microservices offer independent scalability and team autonomy at the cost of distributed systems complexity.
What is the difference between microservices and a monolith?
The monolith vs microservices debate is really about how to organise and deploy software. Both are valid architectures - the right choice depends on team size, product maturity, and operational capability.
The Monolith
All application code is deployed as a single unit. Components communicate via in-process function calls, share the same database, and run in the same process.
Advantages:
- Simple to develop, test, and debug locally
- In-process calls are fast (no network overhead)
- Easy to refactor across component boundaries
- Simple deployment (one artifact, one environment)
- Easy transactions across components (same database)
Disadvantages:
- Scaling requires scaling the entire application, not just the bottleneck component
- Large codebase becomes harder to navigate as the team grows
- Long build/test cycles for the entire application
- A bug in one component can bring down the entire application
- Technology choices are locked in (one language, one runtime)
The Modular Monolith (Middle Ground)
A monolith with clearly defined, independently testable modules with enforced interface boundaries - but still deployed as one unit. This is the pragmatic starting point:
- All the simplicity of a monolith
- Enforced module boundaries make future extraction to microservices easier
- No distributed systems complexity
Microservices
The application is decomposed into small, independently deployable services that communicate over the network (HTTP/gRPC/messaging).
Advantages:
- Independent scaling: scale only the checkout service, not the user profile service
- Independent deployment: teams deploy their service without coordination
- Technology diversity: each service can use the best language/DB for its needs
- Fault isolation: one service crashing doesn't bring down others (with proper circuit breakers)
Disadvantages:
- Distributed systems complexity: network calls fail, latency increases, debugging is harder
- Operational overhead: N services × (monitoring, logging, deployment pipeline, on-call)
- Data consistency: no cross-service ACID transactions; must use Saga patterns
- Testing: integration testing across service boundaries is complex
- Latency: in-process calls (nanoseconds) -> network calls (milliseconds)
Service Boundaries via DDD Bounded Contexts
Domain-Driven Design (DDD) bounded contexts provide a principled way to define service boundaries:
- Bounded context: a domain concept (Order, User, Payment, Inventory) with its own language, model, and data
- Services map to bounded contexts - one service per bounded context
- No sharing of databases between bounded contexts (each service owns its data)
Poor service decomposition (too fine-grained, chatty services) creates a "distributed monolith" - all the complexity of microservices with none of the benefits.
When to Choose Each
| Stage | Recommendation |
|---|---|
| Early startup, < 5 engineers | Monolith (speed over scalability) |
| Growing product, 10-30 engineers | Modular monolith, extract 1-2 critical services |
| Scaled product, 50+ engineers | Microservices (team autonomy justifies operational cost) |
| Specific scale bottleneck | Extract only the service that needs independent scaling |
Interview Angle
Avoid presenting microservices as the obvious "correct" answer. The interviewer wants to hear the tradeoffs. A strong answer: "I'd start with a modular monolith, instrument the codebase to identify bottlenecks, and extract to microservices only when a specific component needs independent scaling or team autonomy justifies the operational overhead."