Back to Library
system_design

Microservices vs Monolith

Monoliths are simpler to build and operate; microservices offer independent scalability and team autonomy at the cost of distributed systems complexity.

architecturepatternsfundamentals

What is the difference between microservices and a monolith?

The monolith vs microservices debate is really about how to organise and deploy software. Both are valid architectures - the right choice depends on team size, product maturity, and operational capability.

The Monolith

All application code is deployed as a single unit. Components communicate via in-process function calls, share the same database, and run in the same process.

Advantages:

  • Simple to develop, test, and debug locally
  • In-process calls are fast (no network overhead)
  • Easy to refactor across component boundaries
  • Simple deployment (one artifact, one environment)
  • Easy transactions across components (same database)

Disadvantages:

  • Scaling requires scaling the entire application, not just the bottleneck component
  • Large codebase becomes harder to navigate as the team grows
  • Long build/test cycles for the entire application
  • A bug in one component can bring down the entire application
  • Technology choices are locked in (one language, one runtime)

The Modular Monolith (Middle Ground)

A monolith with clearly defined, independently testable modules with enforced interface boundaries - but still deployed as one unit. This is the pragmatic starting point:

  • All the simplicity of a monolith
  • Enforced module boundaries make future extraction to microservices easier
  • No distributed systems complexity

Microservices

The application is decomposed into small, independently deployable services that communicate over the network (HTTP/gRPC/messaging).

Advantages:

  • Independent scaling: scale only the checkout service, not the user profile service
  • Independent deployment: teams deploy their service without coordination
  • Technology diversity: each service can use the best language/DB for its needs
  • Fault isolation: one service crashing doesn't bring down others (with proper circuit breakers)

Disadvantages:

  • Distributed systems complexity: network calls fail, latency increases, debugging is harder
  • Operational overhead: N services × (monitoring, logging, deployment pipeline, on-call)
  • Data consistency: no cross-service ACID transactions; must use Saga patterns
  • Testing: integration testing across service boundaries is complex
  • Latency: in-process calls (nanoseconds) -> network calls (milliseconds)

Service Boundaries via DDD Bounded Contexts

Domain-Driven Design (DDD) bounded contexts provide a principled way to define service boundaries:

  • Bounded context: a domain concept (Order, User, Payment, Inventory) with its own language, model, and data
  • Services map to bounded contexts - one service per bounded context
  • No sharing of databases between bounded contexts (each service owns its data)

Poor service decomposition (too fine-grained, chatty services) creates a "distributed monolith" - all the complexity of microservices with none of the benefits.

When to Choose Each

StageRecommendation
Early startup, < 5 engineersMonolith (speed over scalability)
Growing product, 10-30 engineersModular monolith, extract 1-2 critical services
Scaled product, 50+ engineersMicroservices (team autonomy justifies operational cost)
Specific scale bottleneckExtract only the service that needs independent scaling

Interview Angle

Avoid presenting microservices as the obvious "correct" answer. The interviewer wants to hear the tradeoffs. A strong answer: "I'd start with a modular monolith, instrument the codebase to identify bottlenecks, and extract to microservices only when a specific component needs independent scaling or team autonomy justifies the operational overhead."

Recommended Resources