Skip to main content
The Hard Parts.dev
TD-02 Architecture TD Tech Decisions
Severity if wrong · high Freq · common

Modular Monolith vs Distributed Services

Usually a boundary-quality and deployment-independence trade-off.

Severity if wrong
high
Frequency
common
Audiences
architects · staff engineers · platform engineers
Reversibility
hard
Confidence
high
At a glanceTD-02
Really about
Whether the problem is poor modularity or genuine need for runtime/service separation.
Not actually about
Whether the architecture diagram looks more sophisticated.
Why it feels hard
Distributed services feel more explicit, but modular monoliths demand stronger internal discipline.

The decision

Should we enforce boundaries inside one deployable unit or across independently deployed services?

Usually a boundary-quality and deployment-independence trade-off.

Default stance

Where to start before any evidence arrives.

Prefer modular monolith until runtime/service separation is clearly justified.

Options on the table

Two poles of the trade-off

Neither is the right answer by default. Each option's conditions, strengths, costs, hidden costs, and failure modes when misused are laid out in parallel so you can read across facets.

Option A

Modular Monolith

Best when

Conditions where this option is a natural fit.

  • boundaries matter but runtime separation is not yet necessary
  • team count is limited
  • deployment independence is helpful but not dominant
  • refactoring across modules is still common

Real-world fits

Concrete environments where this option has worked.

  • a product with several clear domains but one deployment pipeline
  • a scale-up that needs stronger boundaries before distribution
  • a team wanting better separation without service-operations overhead

Strengths

What this option does well on its own terms.

  • strong internal boundaries with lower operational overhead
  • easier refactoring
  • shared runtime simplicity

Costs

What you accept up front to get those strengths.

  • runtime isolation is weaker
  • poor discipline can collapse boundaries

Hidden costs

Costs that surface later than expected — the main thing novices miss.

  • internal contracts may be treated casually
  • teams can pretend modularity exists when it does not

Failure modes when misused

How this option breaks when applied to the wrong context.

  • Creates a monolith with module-shaped terminology and weak real separation.

Option B

Distributed Services

Best when

Conditions where this option is a natural fit.

  • deployment independence is essential
  • team ownership boundaries are mature
  • runtime isolation matters
  • service economics are justified

Real-world fits

Concrete environments where this option has worked.

  • a mature product platform with real team autonomy
  • a system where scaling, isolation, and release independence are economically justified
  • a business with clear bounded contexts and service operating capability

Strengths

What this option does well on its own terms.

  • clearer runtime separation
  • stronger deployment independence
  • better fault isolation in some cases

Costs

What you accept up front to get those strengths.

  • higher operational burden
  • more coordination overhead
  • network and contract complexity

Hidden costs

Costs that surface later than expected — the main thing novices miss.

  • service separation can freeze poor boundaries
  • debugging cost grows quickly

Failure modes when misused

How this option breaks when applied to the wrong context.

  • Creates service count without service clarity.

Cost, time, and reversibility

Who pays, how it ages, and what undoing it costs

Trade-offs are rarely zero-sum and rarely static. Someone pays, the payoff curve shifts with the horizon, and the decision has an undo cost.

Cost bearer

Option A · Modular Monolith

Who absorbs the cost

  • Current engineering team

Option B · Distributed Services

Who absorbs the cost

  • Platform team
  • Operations
  • Service-owning teams
Time horizon

Option A · Modular Monolith

Often wins in the medium term by buying clarity without full distribution cost.

Option B · Distributed Services

Only wins long-term when separation and ownership are both real and durable.

Reversibility

What undoing costs

Hard

What should force a re-look

Trigger conditions that mean the answer may have changed.

  • Release independence becomes critical
  • Module boundaries stabilize
  • Operational maturity improves

How to decide

The work you still have to do

The reference can frame the trade-off; only you can weight the factors against your context.

Questions to ask

Open these in the room. Answering them is most of the decision.

  • Do we need independent deployment, or just better modularity?
  • Which pain is dominant today: code coupling or runtime/service coupling?
  • Who pays the operations cost if we distribute?
  • Can we describe boundaries clearly without mentioning technology?

Key factors

The variables that actually move the answer.

  • Boundary maturity
  • Deployment independence
  • Team count
  • Runtime isolation needs
  • Ops maturity

Evidence needed

What to gather before committing. Not after.

  • Release contention data
  • Module dependency analysis
  • Boundary and ownership map
  • Ops readiness review

Signals from the ground

What's usually pushing the call, and what should

On the left, pressures to recognize and discount. On the right, signals that genuinely point toward one option or the other.

What's usually pushing the call

Pressures to recognize and discount.

Common bad reasons

Reasoning that feels convincing in the moment but doesn't hold up.

  • Services are more scalable by default
  • Modular monolith sounds like compromise
  • Distribution makes design cleaner automatically

Anti-patterns

Shapes of reasoning to recognize and set aside.

  • Calling packages modules without enforcing boundaries
  • Splitting services while all changes still deploy together
  • Treating runtime distribution as a substitute for design discipline

What should push the call

Concrete signals that genuinely point to one pole.

For · Modular Monolith

Observations that genuinely point to Option A.

  • One deployment is still practical
  • Boundaries need strengthening before distribution

For · Distributed Services

Observations that genuinely point to Option B.

  • Module boundaries are real
  • Deployment contention is costly
  • Runtime isolation matters

AI impact

How AI bends this decision

Where AI accelerates the call, where it introduces new distortions, and anything else worth knowing.

AI can help with

Where AI genuinely reduces the cost of making the call.

  • AI can inspect coupling and propose module/service seams.

AI can make worse

Distortions AI introduces that didn't exist before.

  • AI can mass-produce service wrappers and APIs without proving runtime separation is needed.

Relationships

Connected decisions

Nearby decisions this is sometimes confused with, adjacent decisions that are often entangled with this one, related failure modes, red flags, and playbooks to reach for.

Easy to confuse with

Nearby decisions and how this one differs.

  • That decision is about whether to split deployments at all. This one is about how to enforce boundaries inside a single deployable.

  • That decision is about data ownership across boundaries. This one is about where the boundary line is drawn in the first place.

  • Adjacent concept Package and module housekeeping

    Reorganizing files preserves coupling. This decision is about whether module boundaries stop hidden coupling from spreading.