Filter concepts by levelShowing all levels.

System Design · Monolith vs Modular Monolith vs Microservices

Monolith vs Modular Monolith vs Microservices

What each of the three shapes buys, what microservices specifically cost, and when not to split at all

  • Monolithsimple deploy, local calls, easy transactions
  • Modular monolithboundaries without the network cost
  • Microservicesindependent scaling, deploy, ownership — at a cost
  • When not to splitonly for a named, specific pain

1.Monolith advantages

A monolith deploys as one unit, calls between components are local function calls, a single database means transactions are straightforward, and there is only one thing to operate — one log stream, one deploy pipeline, one set of alerts.

Key features

  • Simpler deployment: one build, one deploy step, no coordinating releases across services
  • Local calls: in-process function calls — no network, no serialization, no partial failure
  • Easier transactions: a single database means multi-table changes can be one ACID transaction
  • Lower operational overhead: one log stream, one deploy pipeline, one on-call surface

The four monolith advantages

The four monolith advantages
AdvantageWhat it meansWhat it avoids
Simpler deploymentone build, one deploy stepcoordinating a multi-service release
Local callsin-process function calls between componentsnetwork latency, serialization, partial failure
Easier transactionsone database, real ACID transactions across tablesdistributed transaction protocols
Lower operational overheadone running system to monitor and operatemanaging N separate deploy pipelines and dashboards
What concentrating everything in one place buys

Simpler deployment

one build, one deploy step

Local calls

in-process, no network

Easier transactions

one database, real ACID

Lower ops overhead

one thing to monitor

  • Simpler deployment — one build, one deploy step
  • Local calls — in-process, no network
  • Easier transactions — one database, real ACID
  • Lower ops overhead — one thing to monitor

Command

text
one deployable + in-process calls + one database
  = simpler deploys, no network between components,
    real ACID transactions, one thing to operate

Monolith: simpler deployment (one build), local calls (no network), easier transactions (one database, real ACID), lower operational overhead (one thing to run).

2.Modular monolith advantages

A modular monolith keeps the plain monolith's single deploy and local calls, while adding enforced boundaries between modules — clearer ownership and lower coupling, without paying for a network between components.

Two independent axes — and the option that only moves along one
Plain monolith
One deploy, in-process calls, and nothing stopping the Orders code from querying the Inventory tables.
Modular monolith
Moves right without moving up. Modules own their own tables and talk through defined interfaces, still inside one deployable.
Microservices
The same boundary benefit, now paid for with deploy pipelines, service discovery and network failure handling.
  • Plain monolith: no enforced boundaries, no network between components — One deploy, in-process calls, and nothing stopping the Orders code from querying the Inventory tables.
  • Modular monolith: real module boundaries, no network between components — Moves right without moving up. Modules own their own tables and talk through defined interfaces, still inside one deployable.
  • Microservices: real module boundaries, network between components — The same boundary benefit, now paid for with deploy pipelines, service discovery and network failure handling.

Command

text
plain monolith:     no boundaries + no network cost
modular monolith:    real boundaries + no network cost
microservices:        real boundaries + network cost

modular monolith gets the boundary benefit
without the network cost

A modular monolith gets clearer boundaries and lower coupling, same as microservices, without paying the network and deployment cost microservices requires.

3.Microservices advantages

Microservices let each service scale independently (only the hot service gets more instances), deploy independently (one team's release does not require coordinating with every other team), and be owned independently (a team can fully own a service's code, data, and on-call).

Key features

  • Independent scaling: a hot service gets more instances without scaling every other service
  • Independent deployment: one service ships without coordinating a release with every other team
  • Independent team ownership: a team can fully own a service's code, data, schema, and on-call
  • These three advantages require the service actually being a separate deployable — a modular monolith does not provide them

The three microservices advantages

The three microservices advantages
AdvantageWhat it meansRequires
Independent scalinga hot service scales alone, not the whole systemthe service running as its own set of instances
Independent deploymentone team ships without coordinating with othersa separate deploy pipeline per service
Independent ownershipa team fully owns a service — code, data, on-callthe service being the unit a team is organized around
What true operational separation buys

Independent scaling

only the hot service scales

Independent deployment

no cross-team release coordination

Independent ownership

a team fully owns code, data, on-call

  • Independent scaling — only the hot service scales
  • Independent deployment — no cross-team release coordination
  • Independent ownership — a team fully owns code, data, on-call

Command

text
each service: own instances (scale) + own pipeline
(deploy) + own team (ownership)

none of the three require any other service to
change, deploy, or scale in lockstep

Microservices buy independent scaling (only the hot service scales), independent deployment (no cross-team coordination to ship), and independent team ownership — all three require true separation, not just separate code.

4.Microservices costs

Microservices pay for their advantages with six concrete costs: network calls replacing function calls, distributed transactions replacing simple ACID ones, harder observability across many services, more operational overhead (multiple pipelines, multiple dashboards), eventual rather than immediate consistency, and new failure modes a monolith never has.

Key features

  • Network calls: every in-process call becomes a network request — latency, timeouts, retries
  • Distributed transactions: no single ACID transaction across services — needs sagas or similar patterns
  • Observability complexity: a single request can span many services — needs distributed tracing to debug
  • Operational overhead: N deploy pipelines, N sets of dashboards and alerts instead of one
  • Eventual consistency: data updated in one service is not instantly visible in another
  • New failure modes: partial failure, cascading failure, retry storms — none of which a monolith has

The six microservices costs

The six microservices costs
CostWhat changesWhat a monolith had instead
Network callsin-process call → HTTP/gRPC calla function call, always available, no latency
Distributed transactionsACID across tables → saga across servicesone BEGIN/COMMIT across all affected tables
Observabilityone request may span N servicesone log stream, one stack trace
Operational overheadN deploy pipelines, N dashboardsone pipeline, one dashboard
Eventual consistencyother services see a change with delayevery read sees the latest committed write
New failure modespartial failure, cascading failure, retry stormsa bug crashes the one process — no cross-service cascade
"Cancel order" spanning three services
Client
Orders
Inventory
Billing
  1. 1cancel order
  2. 2commit locallyOrders now shows "cancelled" immediately
  3. 3order.cancelled event
  4. 4order.cancelled event
  5. 5release reservationprocessed on its own schedule — still shows "reserved" until this runs
  6. 6void the chargeif this call fails, a saga/compensation step is needed — no single ACID commit covers all three
  1. Client → Orders: cancel order
  2. Orders → Orders: commit locally (Orders now shows "cancelled" immediately)
  3. Orders → Inventory: order.cancelled event
  4. Orders → Billing: order.cancelled event
  5. Inventory → Inventory: release reservation (processed on its own schedule — still shows "reserved" until this runs)
  6. Billing → Billing: void the charge (if this call fails, a saga/compensation step is needed — no single ACID commit covers all three)

Command

text
monolith:      1 transaction, 1 dashboard, always
                consistent, calls never "fail" to reach code
microservices: N services = N network calls that can
                fail, N things to monitor, eventual
                consistency, and failure that can cascade

Microservices cost: network calls (latency, timeouts), distributed transactions (sagas, not ACID), harder observability, more operational overhead, eventual consistency, and new failure modes like cascading failure and retry storms.

5.Know when not to split into microservices

Splitting into microservices is not the default good choice — it is justified only when a real, specific pain (independent scaling need, independent team ownership, independent deploy cadence) outweighs the network, transaction, and operational costs. Without that pain, staying a monolith or modular monolith is the better call.

Key features

  • No real scaling difference between components: independent scaling buys nothing if all parts have similar load
  • One team, one release cadence: independent deployment buys nothing if there is no cross-team coordination to remove
  • No genuine team-ownership boundary: independent ownership buys nothing if the same people own everything anyway
  • Operations maturity not yet in place: distributed tracing, service mesh, and on-call practices should exist before the failure modes that need them do
  • A modular monolith is often the correct middle point — real boundaries, without the network cost

Signals for and against splitting

Signals for and against splitting
SignalSuggests
One team owns the whole codebasestay monolith/modular monolith — no ownership boundary to split along
All components have similar, correlated loadstay monolith — independent scaling buys nothing
One release cadence, one on-call rotationstay monolith — no deployment coordination to remove
A specific component has a genuinely different scaling profilea real reason to split that one component out
Distinct teams want to own distinct services independentlya real reason to split along team boundaries
No experience operating distributed systems yetbuild that operational maturity before adding distributed failure modes
Same checklist, two components of one video platform

Transcoding — split it

  • CPU-bound, spikes 50x at peak uploads
  • Everything else stays flat
  • A real, specific scaling difference

Profile/settings — don't split

  • Same team, same release cadence
  • Similar, low, flat load
  • No specific pain identified
  • Transcoding — split it
    • CPU-bound, spikes 50x at peak uploads
    • Everything else stays flat
    • A real, specific scaling difference
  • Profile/settings — don't split
    • Same team, same release cadence
    • Similar, low, flat load
    • No specific pain identified

Command

text
before splitting a component out, name the SPECIFIC
pain it fixes:
  "X needs to scale independently because ___"
  "Team Y needs to deploy independently because ___"
  "Team Z needs to own this because ___"

no specific answer -> don't split yet

Split a component into its own service only when a specific, named pain (real scaling difference, real deployment or ownership boundary) justifies the network and operational cost — not speculatively.

Remember

  • Monolith: simpler deployment, local calls, easier ACID transactions, lower operational overhead.
  • Modular monolith: the same boundary and coupling benefits as microservices, without paying the network cost.
  • Microservices buy independent scaling, deployment and ownership — and cost network calls, distributed transactions, harder observability, more ops overhead, eventual consistency, and new failure modes.
  • Split a component into its own service only for a specific, named pain — never speculatively.

Pro tip

  • The decision is per-component, not all-or-nothing — a modular monolith with exactly one component split out is a legitimate shape.
  • Retries without backoff turn a slow service into a cascading outage — a failure mode a monolith's in-process calls never have.

Next up

  • Client-server and API gateways
  • Load balancing
  • Horizontal vs vertical scaling

Sources

  • System Design Primer — github.com/donnemartin/system-design-primer
  • Checked 2026-08-21

Spotted a mistake on this page? Tell us.