Engineering Leadership & Technical HiringPlaybook3 min readUpdated September 2026

Microservices vs. Monolith: What Actually Justifies the Split

Most "should we move to microservices" conversations start from the wrong premise: that the monolith itself is the problem. Usually it isn't. The problem is that three teams can't deploy independently, or that one noisy code path takes the whole system down with it, and a service split is one possible fix among several, not the automatic answer.

Getting this decision wrong is expensive in both directions. Splitting too early trades a code organization problem for a distributed systems problem, and staying monolithic too long lets deployment coupling quietly cap how fast every team can ship.

The Question to Ask Instead of "Microservices or Monolith"

Ask what's actually being coupled: is it the code, the deployment, or the failure domain? Messy code inside a single service is a refactoring problem, and a service split doesn't fix it, it just moves the mess across a network boundary where it's harder to trace.

A deployment coupling problem looks different: one team's change can't ship without another team's sign off, because their code lives in the same build and release pipeline. That's the pain a service boundary genuinely solves, by giving each team its own deploy pipeline for the piece it owns.

When a Monolith Is Still the Right Answer

If one team owns the whole codebase, or if two or three teams rarely touch the same modules, a monolith with clean internal boundaries usually outperforms a service split on every axis that matters: fewer moving parts to operate, simpler debugging, and no network calls standing in for what used to be a function call.

A monolith also keeps transactions simple. A single database transaction that used to update three related tables becomes a coordination problem across three services once you split them, and that coordination problem is real engineering cost you're taking on, not a side effect you can ignore.

The Signal That Actually Justifies Splitting a Service Out

The strongest signal is a recurring, specific pain: a component with wildly different scaling needs than the rest of the system, or a component whose failures keep taking down unrelated features because they share a process and a deploy. If your recommendation engine needs ten times the compute of everything else, or a flaky third-party integration keeps crashing the whole app instead of just itself, that's a concrete case for isolating it.

A vague sense that "the codebase is getting big" isn't that signal. Size alone is a refactoring problem you can usually solve with better internal module boundaries, without touching your deployment topology at all.

Splitting a service out is justified by signals like these:

  • A component has wildly different scaling needs than the rest of the system.
  • A component's failures repeatedly take down unrelated parts of the system with them.
  • Several teams cannot deploy independently because they are coupled through the same deployment.
  • The pain is recurring and specific, not a general feeling that the codebase is messy.

Where Teams Get Burned Splitting Too Early

The cost that catches teams off guard isn't writing the second service, it's everything that comes with running two services instead of one: distributed tracing to follow a request across a network hop, retry and timeout logic for calls that used to be reliable function calls, and a data consistency story for anything that used to be one database transaction.

Teams that split early usually end up with a distributed monolith: two or more services that still deploy together because they're too tightly coupled to change independently, but now pay the network and operational tax of being separate processes. That's the worst of both models at once, and it's a common enough outcome to plan around rather than assume you'll avoid it.

A Middle Path: Enforce Boundaries Before You Physically Split

Before extracting a service, enforce the same boundary inside the monolith first: a module with a defined interface that the rest of the codebase can only call through, not one that other modules reach into directly for a shortcut. If a team can maintain that discipline inside a single deployable, splitting it out later is mostly an infrastructure change, not a redesign.

If a team can't maintain that discipline inside a monolith, splitting the module into its own service usually doesn't fix the underlying problem either, it just makes the boundary violation a network call and a production incident instead of a code review comment. Fix the discipline first; the physical split is the easy part once the boundary is real.

Executive Capability Standard

What Good Looks Like

Good architectural boundary decisions are driven by a specific, named pain (deployment coupling or failure isolation), with the boundary enforced inside the codebase before it's ever turned into a separate deployable service.

Building The Capability (5-Stage Skill Ladder)

1. Learn:Map which teams currently block on each other's deploys and which components have genuinely different scaling or failure profiles.
2. Do Manually:Enforce a clean interface around one candidate module inside the existing monolith and see whether that alone resolves the coupling pain.
3. Delegate:Assign a senior engineer ownership of defining the extraction criteria so the decision isn't made ad hoc, service by service.
4. Automate:Add contract tests at the module boundary so violations get caught in code review before they become a shipped dependency.
5. Buy:Bring in an engineer who has run a service extraction before if your team is attempting its first split on a system that can't afford a failed attempt.

How to Get Started

Frequently Asked Questions

How many services is too many for a five person engineering team?

There's no fixed number, but watch for the symptom rather than counting services: if engineers spend more time coordinating deploys and chasing a request across services than writing features, you've likely split further than your team size can operate well. Consolidating two rarely-changed services back together is a legitimate move, not a failure.

Do we need Kubernetes to run more than one service?

No. A handful of services can run on simpler infrastructure, a couple of managed containers or a platform as a service, without the operational overhead of running an orchestrator yourselves. Kubernetes earns its complexity at a scale of services and traffic most small teams haven't reached yet.

What's usually the first service worth splitting out of a monolith?

Whichever component has the clearest, most painful scaling or failure isolation need right now, not the one that's theoretically the cleanest boundary on a whiteboard. A background job processor or a single flaky external integration is a common first candidate, since isolating it has an immediate, measurable benefit.

About the numbers

This guide doesn't quote a sourced benchmark. Figures in it are estimates or general guidance, so check them against your own numbers.

Related Guides