Why Your Microservices Are Just a Distributed Monolith (And That's the Problem)
šŸ’» code

Why Your Microservices Are Just a Distributed Monolith (And That's the Problem)

System Design: What Nobody Tells You About Building Scalable Systems

Part 1 of 1

System Design: What Nobody Tells You About Building Scalable Systems

View all chapters →
Devesh Korde

Devesh Korde

September 12, 2026

šŸ“– 9 min read
#System Design#Microservices#Architecture#Distributed Systems#Production
⚔ TL;DR
  • Microservices solve monolith problems by adding distribution, but distribution introduces new problems: network latency, cascading failures, partial outages, and debugging nightmares
  • The coupling moved from code to the network. Services depend on each other through APIs. When one service is slow, every service that calls it becomes slow. The system is still tightly coupled, just in a different way
  • Most organizations are not ready for microservices. They lack the observability, resilience patterns, and operational maturity. They ship microservices and get a distributed monolith: all the complexity, half the benefits
  • You should use microservices if: you have independent deployment needs, separate scaling requirements, or truly isolated business domains. You should NOT use microservices if: you just wanted to decouple your codebase. Use modular architecture instead

I watched a company spend six months breaking their monolith into microservices.

The architecture looked beautiful on the whiteboard. Twenty services. Each with its own database. Each with its own CI/CD pipeline. Each supposedly independent.

In production, after the first scaling test, everything broke. A search service got slow. Users waiting for search results timed out. Those timeouts propagated to the recommendation service. The recommendation service timed out. The timeout propagated to the user service. The user service crashed.

One slow service crashed the entire system.

They had a microservices architecture. The system failed like a monolith. Worse: it failed in ways a monolith never would.

The problem was not the microservices. The problem was that they had created a distributed monolith. All the downsides of microservices. None of the upsides.

What a Monolith Actually Is

A monolith is one codebase. One deployment. One database. One process.

The problem with a monolith is clear: if you change one line in one service, you redeploy the entire application. If one service crashes, everything crashes. Code changes in service A can break service B. Everything is tightly coupled through shared code.

The solution seems obvious: break it into microservices.

What Microservices Promise

Microservices promise:

  • Independent deployment (change service A, do not redeploy service B)
  • Independent scaling (service A is slow, scale it without scaling everything)
  • Technology independence (service A is Node.js, service B is Java, service C is Go)
  • Team independence (team A owns service A, team B owns service B, no coordination needed)
  • Fault isolation (service A crashes, service B stays up)

All of this is true. In theory.

What Microservices Actually Deliver

In practice, you get a distributed monolith. Here is why.

The Coupling Moved

You removed code-level coupling. But you introduced network-level coupling.

Service A calls Service B. Service B calls Service C. They are still tightly coupled. The coupling is just at the network level instead of the code level.

When Service B is slow, Service A waits. Service A becomes slow. Service A's clients wait. The slowness propagates.

You have not decoupled anything. You have just made the coupling invisible and harder to debug.

The Failures Are Harder

In a monolith, if a service crashes, you get a crash. Everything stops. It is clear something went wrong.

In a distributed monolith, failures are subtle. Service B is slow. Service A times out. Service A retries. Service A times out again. Service A's circuit breaker opens. Service A returns errors. Clients see errors from Service A.

Did Service A fail? No. Service B failed. But the error originated in Service A. The failure cascaded.

A developer looking at Service A logs sees errors. They have no idea the real problem is Service B.

The Operational Complexity Is Exponential

A monolith needs:

  • Logging
  • Monitoring
  • Deployment pipeline
  • Health checks

A microservices architecture needs:

  • Logging for each service + correlation IDs to trace requests across services
  • Monitoring for each service + distributed tracing to understand where failures originate
  • Deployment pipeline for each service
  • Health checks for each service + dependency health checks
  • Service discovery (how do services find each other?)
  • Load balancing (how do requests route to the right service instance?)
  • Circuit breakers (how do services stop calling broken services?)
  • Retry logic (how do services recover from transient failures?)
  • Rate limiting (how do services protect downstream services from overload?)
  • API versioning (how do services evolve without breaking clients?)

The operational complexity is not 20x (20 services vs. 1). It is exponential. Because every service depends on every other service, and failures in one cascade to all.

Example: The Cascading Failure

You have 10 services. A deploy goes wrong in one service. The service starts returning errors. It is only 10% of your traffic.

Here is what happens:

  1. Service A returns errors (deployed bad code)
  2. Service B calls Service A, gets errors, retries
  3. Service B's retry logic burns through its thread pool
  4. Service B becomes slow
  5. Service C calls Service B, gets timeouts
  6. Service C opens its circuit breaker
  7. Requests to Service C fail
  8. Service D calls Service C, gets failures
  9. Service D starts returning errors to users

One service returning 10% errors cascades into 90% of the system being unavailable.

In a monolith, one deploy rolls back. One fix. Problem solved.

In a distributed monolith, you have to:

  1. Identify which service is failing (requires tracing across 10 services)
  2. Identify why the failure cascaded (requires understanding all the dependencies)
  3. Fix the circuit breakers, timeouts, and retry logic
  4. Redeploy multiple services to fix the cascading failure

The failure was simple. The fix is complex.

Why Companies Ship Distributed Monoliths

Most companies break their monolith into microservices for the wrong reason.

Reason 1: Scalability Theater

"Our monolith does not scale. We need microservices so we can scale individual services."

This is true. But scaling a monolith is easier than managing a distributed monolith.

Before microservices: scale the monolith by adding more instances. Load balancer distributes traffic. Done.

After microservices: scale Service A by adding more instances. Now manage inter-service communication. Now debug cross-service failures. Now monitor distributed tracing.

The scalability problem was real. The solution created worse problems.

Reason 2: Deployment Fear

"We want to deploy Service A without deploying Service B."

This is a real need. But it does not require microservices. Modular architecture with clearly defined interfaces solves this.

Deploy modules instead of services. Same benefits. None of the distributed complexity.

Reason 3: Team Organization

"We have 10 teams. Each team should own a service."

This is the worst reason. Because now you have 10 teams coordinating across network calls instead of coordinating through code reviews.

Team A makes a change to the API. Team B did not update their client code. Failure at runtime.

You have not reduced coordination. You have just moved it from the codebase to the network.

Reason 4: Hype

Microservices are popular. Netflix uses them. Uber uses them. Amazon uses them.

What they do not tell you: Netflix, Uber, and Amazon have entire teams dedicated to making microservices work. They have built distributed systems infrastructure that most companies do not have.

They have observability tools. Circuit breakers. Service meshes. Chaos engineering. Years of experience.

Most companies shipping microservices have none of this.

The Real Tradeoff

Microservices are not bad. They are just not a universal solution.

The tradeoff is:

Monolith:

  • Simple to understand
  • Simple to deploy
  • Easy to debug
  • Couples everything
  • Hard to scale individual components

Microservices:

  • Complex to understand
  • Complex to deploy
  • Hard to debug (requires distributed tracing)
  • Decouples services (but couples them through the network)
  • Easy to scale individual components
  • Requires operational maturity you probably do not have

The question is: what problem are you actually solving?

If the problem is "our codebase is too big to understand," microservices does not solve it. You still have a big codebase, now distributed across 20 services.

If the problem is "we want independent deployment," you can solve it with modular architecture and clear interfaces.

If the problem is "our monolith does not scale," you can solve it by scaling the monolith. Most monoliths can handle 10x more load just by adding more instances.

If the problem is "we want different teams working independently," microservices creates new problems: coordinating across network calls is harder than coordinating through code.

When Microservices Actually Make Sense

Microservices make sense when:

  1. You have truly independent domains
- User service is completely independent from Product service

- They have different data models, different business logic, different scaling requirements

- They do not need to coordinate

  1. You have separate operational requirements
- Service A needs to scale to 100,000 requests/second

- Service B is fine at 1,000 requests/second

- Scaling them independently saves money and complexity

  1. You have different technology requirements
- Service A must be built in Java for performance

- Service B works fine in Python

- The language mismatch is a blocker for a monolith

  1. You have deployment constraints
- Service A changes daily

- Service B changes monthly

- Redeploying Service B every time Service A changes is wasteful

If none of these are true, you do not need microservices. You need better code organization.

The Uncomfortable Truth

Most companies using microservices are experiencing:

  • Higher operational complexity
  • Harder debugging
  • More cascading failures
  • Higher latency (network calls are slower than function calls)
  • Higher infrastructure costs (maintaining 20 services costs more than maintaining 1)

And they are not getting:

  • Easier deployment (most teams deploy services together anyway)
  • Better scalability (the bottleneck is usually not the service, it is the database)
  • Better fault isolation (failures cascade)
  • Better team independence (services depend on each other)

They built a distributed monolith. They got the downsides of both architectures.

What You Should Do Instead

Step 1: Be honest about your problem

Do you have a scalability problem? Or a code organization problem? They require different solutions.

Step 2: Try modular architecture first

Break your codebase into modules. Each module has clear boundaries. Each module has its own database schema (in the same database). Each module can be deployed independently (with careful coordination).

You get decoupling without distribution.

Step 3: Only use microservices when necessary

Once you have proven that modularity does not scale, then consider microservices. Not before.

Step 4: Build operational maturity

If you use microservices, invest in the infrastructure: distributed tracing, circuit breakers, service mesh, chaos engineering, chaos testing.

Do not ship microservices without this. You will regret it.

The Architecture Diagram Lie

The microservices architecture diagram shows 20 boxes, each independent.

The reality is 20 boxes with hundreds of arrows between them. Each arrow is a dependency. Each dependency is a failure point.

Do not optimize for the diagram. Optimize for the reality.


Microservices are not bad. But they are not a silver bullet. They solve specific problems at the cost of introducing new problems.

Most companies do not have the specific problems that microservices solve. They ship microservices anyway and get a distributed monolith.

Be honest about what problem you are solving. Then pick the architecture that solves that problem without creating new ones.

Most of the time, that architecture is not microservices.


šŸŽ‰ You've finished System Design: What Nobody Tells You About Building Scalable Systems

← Back to all articles

Related Articles