Architecture Pattern Guide

When Not to Use Microservices

Goal

The previous sections explained what makes microservices useful. This section is just as important: microservices are not the default destination for every system.

Microservices can be powerful when the system needs independent ownership, deployment, scaling, and failure isolation. They can also slow a team down when the domain is unclear, the team is small, or the operating model is immature.

The durable idea is:

Microservices are expensive when boundaries are unclear or operations are immature.

The Short Version

The tempting story is:

If the system is hard to change, split it into microservices.

The more practical story is:

Split only the parts whose independence is worth the distributed-system cost.

A modular monolith can be a strong architecture. It is one deployable application with disciplined internal boundaries. Catalog, orders, payments, and inventory can exist as clear modules without becoming separate runtimes immediately.

That approach may be better when the product is young, one team owns most of the work, domain boundaries are still changing, or operations are not ready for distributed telemetry, retries, message recovery, and many deployments.

Warning Signals

Microservices are likely to hurt more than help when several of these are true:

SignalWhy It Matters
The team cannot name stable business capabilities.Services will be split around guesses or technical layers.
One small team owns the whole product.Distributed ownership may add ceremony without enough benefit.
Releases are already slow because testing is weak.More services can make test environments and compatibility harder.
Observability is immature.Distributed failures will be hard to diagnose.
Deployment automation is weak.Independent services create more release paths to manage.
Data ownership is unclear.Shared writes will recreate coupling behind service APIs.
Every feature needs changes across every service.The boundaries are too split or too coupled.
The main motivation is trend, resume value, or platform standardization.The design may not be tied to business independence.

None of these signals bans microservices forever. They point to work that should happen before or alongside service extraction.

When a Modular Monolith Is Better

A modular monolith is often a better starting point when the team wants better boundaries but not separate runtime ownership yet.

It can still enforce discipline:

  • Modules have clear names and responsibilities.

  • Internal dependencies are controlled.

  • Data access rules are explicit.

  • Tests protect module behavior.

  • The team can later extract a stable boundary into a service.

The key is not to let "monolith" mean "unstructured." A modular monolith should be intentionally designed. It gives the team a place to learn the domain before paying the full cost of distribution.

Evolution Path

Service extraction can be gradual:

Unclear domain or small team
  -> Modular monolith or fewer services

Clear module boundary and repeated independent change pressure
  -> Candidate service boundary

Stable capability and strong operations
  -> Extract service with owned data, contracts, deployment, and telemetry

For example, an early commerce product may keep catalog, cart, checkout, and admin functions in one modular application while extracting payment integration later. Payments may deserve separation because it has distinct security, audit, partner integration, and failure behavior. Recommendations may also become separate when it changes frequently and can degrade without blocking checkout.

The admin back office may remain a module for a long time if one team owns it, change pressure is low, and independent scaling is not important. That is not architectural weakness. It is focus.

Decision Filter

Before extracting a service, ask:

  1. Does this capability have a clear owner?

  2. Does it have different change, scale, reliability, security, or compliance needs?

  3. Can its data boundary be owned without uncontrolled shared writes?

  4. Can consumers use an API, message, or event contract instead of internals?

  5. Can it deploy independently without breaking consumers?

  6. Can failures be isolated, observed, and recovered?

  7. Is the benefit of independence larger than the cost of distribution?

If the answer is mostly no, improve the module boundary first.

Common Mistakes

  • Using microservices to compensate for unclear code ownership.

  • Splitting before the domain is understood.

  • Adopting distributed systems without observability and deployment automation.

  • Calling a distributed monolith microservices.

  • Treating a modular monolith as failure instead of a valid architecture choice.

  • Extracting services without data ownership and contract versioning.

If Someone Asks You

When should a team avoid microservices?

A good answer is:

I avoid microservices when boundaries are unclear, one small team owns the whole product, deployment and observability are immature, or every feature would still require coordinated changes across many services. In that situation, I prefer a modular monolith or fewer services with clear internal boundaries. I extract a service only when a stable capability needs independent ownership, deployment, scaling, data, reliability, or security behavior.

What You Should Remember

Do not distribute what the team cannot own, observe, and change safely.

Questions to Check Understanding

  1. What signals suggest a modular monolith is better?

  2. Why can early microservice extraction slow a team down?

  3. What should be true before extracting a service?