Microservices vs Monolith

Architecture choice. Default to monolith unless specific pain points demand splitting.

1 credit

Monolith — the right default

  • One codebase, one deploy, one DB. Simple to reason about.
  • Refactoring across features = single PR. No API coordination.
  • Local dev = one process. No docker-compose with 12 services.
  • DB transactions work. No distributed consistency problems.
  • At <50 engineers and <10M req/day, monolith almost always wins.

When to split

  • Team size: one codebase becomes a merge-conflict zoo (~30+ active engineers).
  • Different tech stacks — ML (Python), API (Go), website (TypeScript) legitimately different.
  • Different scale/cost profiles — image processing needs GPU; auth API needs lots of small instances.
  • Different release cadences — billing team ships monthly; product team ships hourly.
  • Regulatory isolation — PII subsystem needs VPC + separate audit.

Hidden microservices costs

5 items
Network calls are slow + unreliable
In-process call: 1µs. HTTP call: 1-10ms + failure modes
Distributed transactions
You can't. Use sagas, outbox pattern, or eventual consistency
Debugging across services
Need traces (OpenTelemetry), correlation IDs, log aggregation
Ops complexity
N services × deploy + monitor + secrets + alerts + on-call
Data ownership
Shared DB schemas leak across services. Each service needs its own tables

Modular monolith (the middle path)

  • Keep one deploy, but enforce internal module boundaries — `billing/` can't import from `feed/` directly.
  • Each module owns its DB tables; cross-module reads go through a service interface.
  • If a module needs to split out later, the boundary is already drawn. Cheap migration.
  • Shopify, GitHub, Basecamp all run this pattern at huge scale.

Further reading