Contents

Architecture & System Design › Architecture Styles

Monolith vs Microservices

Weighing simplicity against independent scaling and deployment.

Also known as: monolith or microservices, monolith vs microservice, microservices vs monolith, when to use microservices

A monolith is deployed as one unit. Microservices split the system into many independently deployed services (monolith, microservices). Neither is “better”. They trade different costs.

MonolithMicroservices
DeploymentOne artifact, one releaseMany, each independent
ComplexityIn the codebaseIn the system: network, versions, infrastructure
Calls between partsIn-process, fast and reliableOver the network: latency, failures, retries
Transactions and consistencySimple (one database transaction)Hard: sagas, eventual consistency (sagas)
Debugging and testingEasier: one process, one logHarder: distributed tracing, many logs, integration tests
ScalingScale the whole thingScale services independently
Team autonomyTeams share a codebase and a releaseTeams own services end to end
Technology choicesOne stackFree choice per service (and more to maintain)
Fault isolationA bug can take down everythingFailures can be contained (if designed for it)
Operational overheadLowHigh: CI/CD per service, discovery, monitoring, security
Starting speedFastSlow: infrastructure first

What really drives the choice

Team size and organization. Microservices mostly solve an organizational problem: many teams stepping on each other. With one team or a handful, the overhead usually outweighs the benefit. Conway’s law applies: systems mirror communication structures.

Operational maturity. Microservices require solid automation, observability and on-call practices. Without them, you get chaos.

Different scaling or reliability needs among parts of the system.

Domain understanding. Service boundaries are hard to get right early. Wrong boundaries are expensive to fix, much more so than module boundaries in a monolith.

The usual advice

  1. Start with a (modular) monolith. Keep clean module boundaries and owned data (modular monolith).
  2. Extract a service when there’s a concrete reason: a different scaling profile, a team that needs independent deployment, a part needing a different technology or isolation.
  3. Avoid the worst of both worlds: the distributed monolith, services so coupled (shared database, synchronous call chains, lockstep releases) that you pay microservices’ costs without their benefits.

Questions to ask

  • What problem are we trying to solve, and is it a code problem, a team problem or a scaling problem? Would better modularity fix it?
  • Can we run, monitor and debug a distributed system?
  • How will we handle data consistency across services?
  • What happens when one service is down?
  • Is there a cheaper step (module boundaries, a separate worker process, a managed service) that gets most of the benefit?

Decide with the actual constraints in front of you, record the reasoning (architecture decision record), and be willing to change course (architectural trade-offs).