Back
Interactive Explainer

Microservices vs Monolith: Choosing the Right Architecture

The real costs and benefits of microservices vs monoliths, the strangler fig migration pattern, service boundaries, and how to make the architectural decision for your team size and stage.

🎯Key Takeaways
Start with a monolith — microservices are an organizational solution to an organizational problem
Split by bounded context (business domain), not by technical layer
The hidden costs: distributed transactions, operational overhead, network latency, developer experience complexity
Strangler fig: migrate from monolith incrementally — never big-bang rewrite
Modular monolith gives 80% of the benefits with 20% of the operational cost
Adopt microservices only when you have concrete reasons: team size, differential scaling, reliability requirements

Microservices vs Monolith: Choosing the Right Architecture

The real costs and benefits of microservices vs monoliths, the strangler fig migration pattern, service boundaries, and how to make the architectural decision for your team size and stage.

~5 min read
Be the first to complete!
What you'll learn
  • Start with a monolith — microservices are an organizational solution to an organizational problem
  • Split by bounded context (business domain), not by technical layer
  • The hidden costs: distributed transactions, operational overhead, network latency, developer experience complexity
  • Strangler fig: migrate from monolith incrementally — never big-bang rewrite
  • Modular monolith gives 80% of the benefits with 20% of the operational cost
  • Adopt microservices only when you have concrete reasons: team size, differential scaling, reliability requirements

Lesson outline

The microservices hype cycle

In 2015-2020, "microservices" became synonymous with "modern engineering." Companies decomposed their monoliths into dozens of small services, hired DevOps teams to manage them, and then wondered why they were slower than before. Netflix, Amazon, and Google run microservices — but they have thousands of engineers to manage them.

The truth: microservices are an organizational solution to an organizational problem. They make sense when multiple teams need to deploy independently, when parts of the system have wildly different scaling requirements, or when you need technology diversity. For most startups and small teams, they are premature.

Start with a monolith — Martin Fowler agrees

"Don't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile." — Martin Fowler. Build a well-structured monolith with clear module boundaries. Decompose only when you have a specific, concrete reason.

Honest comparison: what you gain and what you pay

ConcernMonolithMicroservices
Development speed (early)⚡ Fast — one codebase, one deploy🐢 Slow — service boundaries, API contracts, local dev setup
Development speed (at scale)🐢 Slow — merge conflicts, big teams on one repo⚡ Fast — teams deploy independently
Operational complexity✅ Simple — one process to monitor❌ Complex — service mesh, distributed tracing, many failure modes
Scaling flexibility❌ Scale the whole app even if one part is hot✅ Scale each service independently
Technology diversity❌ One language/framework✅ Right tool per service
Distributed system problems✅ No network calls, no partial failures❌ Must solve: distributed transactions, circuit breakers, service discovery
Developer experience✅ Run locally with one command❌ Requires Docker Compose with 10+ services, or remote dev environment

The hidden cost of microservices: latency (network calls replace in-process), consistency (distributed transactions are hard), operational burden (each service needs its own CI/CD, monitoring, scaling policy, on-call runbook).

Service boundary design: how to split correctly

The most common microservices mistake: splitting by technical layer (user-facing service, business logic service, data access service). This creates chatty, coupled services that deploy together anyway. It is not microservices — it is a distributed monolith.

Split by bounded context (Domain-Driven Design): Each service owns one business domain — Users, Orders, Inventory, Payments, Notifications. The domain owns its data (no cross-service joins). Cross-domain operations use APIs or events.

Signs you have the boundary wrong: Services must be deployed together to function, or services frequently call each other synchronously in a chain (A → B → C → D — this is a monolith over the network).

Team ownership: "You build it, you run it" — each service is owned by one team end-to-end. If two teams own the same service, it is not really microservices. Conway's Law: your architecture reflects your team structure.

Two-pizza team rule for service sizing

A service should be manageable by a two-pizza team (6-8 engineers). If it requires more, split it further. If one engineer can manage 5 services, consider merging some. Service granularity should match team granularity.

The strangler fig pattern: migrating from monolith

The strangler fig plant grows around a host tree, eventually replacing it. The Strangler Fig Pattern applies the same idea to software migration: gradually replace monolith functionality with new services, one piece at a time, until the monolith is gone (or just a thin shell).

Steps: (1) Add a routing layer (API gateway or reverse proxy) in front of the monolith. (2) Choose one module to extract — pick one that is clearly bounded and not deeply coupled. (3) Build the new service. (4) Route traffic for that domain to the new service via the routing layer. (5) Delete the old code from the monolith. (6) Repeat.

Anti-pattern: big-bang rewrite. Rewriting the entire monolith from scratch (Duke Nukem Forever antipattern). The new system is never feature-complete before the old one rots. The strangler fig is safer: always have a working system, migrate incrementally.

The routing layer (API gateway) is the key. It is the seam between old and new. Keep it simple — just proxy routing, no business logic.

strangler-fig-nginx.conf
1# Strangler Fig routing layer
2# Gradually route domains from monolith to new microservices
3
4server {
5 listen 443 ssl;
6 server_name api.example.com;
7
8 # ✅ Migrated: route to new Users microservice
Migrated routes go to new services; unmigrated fall through to monolith
9 location /api/users/ {
10 proxy_pass http://users-service.internal:4001;
11 }
12
13 # ✅ Migrated: route to new Payments microservice
14 location /api/payments/ {
15 proxy_pass http://payments-service.internal:4002;
16 }
17
18 # 🔄 In progress: Orders being migrated
19 # location /api/orders/ {
20 # proxy_pass http://orders-service.internal:4003;
21 # }
22
The monolith is still the default — no traffic disruption during migration
23 # ⬛ Not yet migrated: everything else still goes to monolith
24 location / {
25 proxy_pass http://monolith.internal:3000;
26 proxy_set_header X-Forwarded-Host $host;
27 }
28}
29# Migration progress: Users ✅, Payments ✅, Orders 🔄, Inventory ⬛, Notifications ⬛

When to choose microservices: the honest checklist

Consider microservices when:

  • You have multiple independent teams (>50 engineers)Each team can own and deploy their service without coordinating with others.
  • Parts of the system have wildly different scale requirementsYour image processing needs 100x the resources of your user auth service.
  • You have different reliability requirements per domainPayments needs 99.99% uptime; analytics can tolerate 99.9%.
  • You need technology diversityML model serving in Python, real-time processing in Go, web API in Node.js.
  • You are a startup with < 20 engineersOperational overhead will slow you down more than it helps.
  • Your monolith is well-structured with clear modulesA modular monolith often gives 80% of the benefit with 20% of the cost.
How this might come up in interviews

Architecture questions test judgment and the ability to reason about trade-offs, not knowledge of patterns.

Common questions:

  • When would you choose microservices over a monolith?
  • How would you migrate a monolith to microservices?
  • What are the hidden costs of microservices that are not obvious upfront?
  • Explain Domain-Driven Design and bounded contexts.

Strong answers include:

  • Starts with "it depends" and asks about team size and scaling requirements
  • Knows the strangler fig pattern for migration
  • Mentions distributed transaction complexity as a real cost
  • Has a nuanced view of when NOT to use microservices

Red flags:

  • Always recommends microservices as the "modern" choice
  • Cannot explain bounded contexts or DDD
  • Does not know what a modular monolith is
  • Cannot explain the operational overhead of microservices

Quick check · Microservices vs Monolith: Choosing the Right Architecture

1 / 1

Your 10-engineer startup is deciding between a monolith and microservices. Which factors most strongly favor a monolith?

Key takeaways

  • Start with a monolith — microservices are an organizational solution to an organizational problem
  • Split by bounded context (business domain), not by technical layer
  • The hidden costs: distributed transactions, operational overhead, network latency, developer experience complexity
  • Strangler fig: migrate from monolith incrementally — never big-bang rewrite
  • Modular monolith gives 80% of the benefits with 20% of the operational cost
  • Adopt microservices only when you have concrete reasons: team size, differential scaling, reliability requirements

From the books

Building MicroservicesSam Newman (2021)

Chapter 1: What Are Microservices?

The author of the definitive microservices book now cautions against them for most organizations: "I would be cautious about adopting microservices unless you have a specific need that they address."

Ready to see how this works in the cloud?

Switch to Career Paths for structured paths (e.g. Developer, DevOps) and provider-specific lessons.

View role-based paths

Sign in to track your progress and mark lessons complete.

Discussion

Questions? Discuss in the community or start a thread below.

Join Discord

In-app Q&A

Sign in to start or join a thread.