Monolith vs Microservices — When to Split and Why
Choose service boundaries carefully. Microservices solve team and scale problems but add distributed complexity.
A monolith is a single application that does everything: one codebase, one deployment, one database. Microservices split that into independent services that each own a specific business capability — each deployed, scaled, and updated independently.
The monolith gets a bad reputation it doesn't deserve. A well-structured monolith is simpler to develop, test, debug, and operate than microservices. You don't need distributed tracing, service discovery, or a service mesh. The database is one place. Deployments are one step. This is why most successful startups begin as monoliths — because the operational overhead of microservices is a tax that doesn't pay off until you have real scaling or team size problems.
Microservices shine when specific services have fundamentally different scaling requirements (your image processing service needs 100× more compute than your auth service), when teams are large enough that deploying a monolith creates coordination overhead, or when you need to use different technology stacks per domain. The key insight: microservices are primarily an organizational solution, not a technical one. Don't split a monolith because it 'feels right' — split it when you have a concrete team or scaling problem that microservices actually solve.
Key concepts
Step-by-step approach
- 1
Assess the actual problem: is the bottleneck deployment coordination (team size), independent scaling (specific service 100× hotter), or technology choice? Microservices solve organizational problems.
- 2
Before splitting, build a modular monolith: organize the monolith into well-defined modules with clean internal APIs, even if they deploy together.
- 3
Map bounded contexts using DDD event storming: identify the natural domain boundaries where a different ubiquitous language applies.
- 4
Split services along bounded contexts, never along technical layers (no separate 'database service' — own your data per service).
- 5
Establish service contracts: each service publishes an API contract (OpenAPI or gRPC schema) and versioning policy before any consumers are built.
Key trade-offs
Independent deployment vs. distributed complexity
each microservice can be deployed independently — faster iteration per team. But now you have distributed transactions, service discovery, network failures, and eventual consistency to manage.
Technology diversity vs. operational overhead
microservices allow each team to pick the right tool. But running 10 different languages/frameworks means 10× the expertise required in SRE, monitoring, and on-call.
Scalability vs. latency
microservices allow per-service scaling, but a single user request may now fan out to 5-10 services. Each service hop adds latency and a potential failure point.
Common pitfalls
Splitting a monolith too early: premature decomposition creates the operational overhead of microservices without the scaling benefit. Most teams should build a modular monolith first.
Sharing a database between microservices: two services sharing a database are not independent — a schema change in one breaks the other. Each service must own its data store.
Distributed monolith: splitting along technical layers (auth service, data service, UI service) instead of business boundaries creates services that can only deploy together — the worst of both worlds.
Interview questions on this topic
Practice answering these with AI feedback → Start on CrackLab
Continue learning — explore 207 more topics on CrackLab DesignHub
From Classic HLD designs (Twitter, YouTube, Uber) to LLD patterns, distributed systems, databases, and company case studies.
Related topics
Services need to find each other and receive safe runtime configuration in changing environments.
Distribute traffic across healthy backends using L4/L7 algorithms and health checks.
Move static and cacheable content close to users to reduce latency and origin load.