Blog The case against premature microservices

The case against premature microservices

2 min read

The case against premature microservices
TL;DR Microservices trade in-process simplicity for network complexity: distributed failures, deployment overhead, and data consistency across services. Those costs are worth it at real scale and with many teams. Before that, a well-structured monolith ships faster and is far easier to change. Split only when a real boundary demands it.

Microservices are a genuinely good answer to real problems, at real scale, with the right team structure. Reaching for them before you have those conditions is one of the more expensive mistakes in modern architecture. Here is the case for waiting.

What microservices actually cost

Splitting an application into services does not remove complexity; it moves it from inside your process to the network between services. And network complexity is the hard kind.

  • Distributed failure. A call that was a function is now a network request that can time out, fail, or arrive twice. You have to handle all of it.
  • Data consistency. State that lived in one database now spans services, so keeping it consistent becomes a distributed problem.
  • Operational overhead. More services means more to deploy, monitor, version, and debug across boundaries.

These are worth paying when they buy you something. Early on, they buy you very little.

When the trade pays off

Microservices earn their cost under specific conditions:

  • Scale a single deployment cannot handle, so parts genuinely need to scale independently.
  • Multiple teams that need to deploy on their own cadence without coordinating every release.

Notice both are about a boundary you actually have, a scaling limit or an organisational one, not one you are guessing you will hit someday.

The monolith that is not a mess

The alternative to premature microservices is not a tangled ball of mud. It is a well-structured monolith: one deployable application with clear internal modules and defined boundaries between them. You get separation of concerns without paying the network tax, and you ship faster because a change is one deploy, not a coordination exercise.

The bonus is that a well-structured monolith is the best possible starting point for extracting a real service later. When a genuine boundary appears, a clean module is easy to pull out. A muddy one is not, but that is an argument for structure, not for services.

The pragmatic path

Start with a structured monolith. Keep the boundaries between modules clean. Split out a service only when a real, present pressure, scale or team independence, demands it, and split exactly at that boundary. You will ship sooner, change faster, and take on distributed-systems complexity only when it is actually buying you something. That is the opposite of premature, and it is usually the faster road even to the scale where microservices finally make sense.

FAQ

What is wrong with starting with microservices?

You take on the hard parts of distributed systems, network failures, latency, data consistency across services, deployment and monitoring overhead, before you have the scale or team size that makes those tradeoffs pay off. You pay the cost early and get the benefit late, if at all.

When do microservices actually make sense?

When you have real scale that a single deployment cannot handle, or multiple teams that need to deploy independently without stepping on each other. The driver should be an organisational or scaling boundary you actually have, not one you imagine you will.

Is a monolith just a big ball of mud?

Not if it is structured. A well-organised monolith has clear internal modules with defined boundaries. That gives you most of the separation benefits without the network cost, and it makes it far easier to extract a real service later if you genuinely need to.