Skip to main content

Good Monoliths Are Underrated

· 6 min read
Malcolm Navarro
Director of Engineering @ Messari

Hot take to start the 2026 calendar year: Microservices were a psyop created to manufacture work and "fix" poor coding decisions. In most cases, a modular monolith makes more sense.

Are microservices a valid concept? Yes! Are there benefits when compared to a traditional monolith at scale? Without a doubt! However, the industry has over-indexed on microservices as a means to create separation of concerns, enable better parallelization / ownership and stop bad coding deciions by fragmenting the code. In this post, I'll be talking about when and how a monolith makes sense, and when it doesn't.

TLDR; it all hinges on scale.

Separation of Concerns​

When the often asked question of "Does it make sense to put this here?" is asked, separation of concerns is at the top of the engineering decision tree. For example, the add() function should only be doing addition and the MathService should only be doing math. Does this service concern itself with what I'm trying to do?

With microservices, seperations of concerns is an inherently solved problem. The entire service has a name, hopefully a good one, that clearly explains what it's purpose is. Anything outside of that scope should be in another service. Oh, there is no good home, make another one! (Plz don't)

However, there is nothing stopping us from doing the same within a monolith. It just requires more meticulous code reviews and deeper understanding of the broader code base. Because there are no microservice walls creating the separation, the engineers must do this procedurally, in code.

Parallelization / Ownership​

One of the biggest selling points of microservices is enabling parallel development across teams. The argument goes: "Team A owns the Payments service, Team B owns the Users service, and they can deploy independently without stepping on each other's toes."

Fair point. But let's be real—how often is this the actual bottleneck?

In most organizations (especially startups and mid-sized companies), you don't have 50 engineers fighting over the same codebase. You have 5-15 engineers who can coordinate effectively with good git hygiene and clear module boundaries. The "we need microservices for parallel development" argument often comes from engineers who worked at FAANG and are applying solutions designed for thousands of engineers to teams of twelve.

Within a well-structured monolith, ownership can be established through:

  • Clear module/package boundaries - The payments/ directory is owned by the payments team
  • CODEOWNERS files - Enforce review requirements per directory
  • Feature flags - Deploy code without releasing it, reducing merge conflicts
  • Trunk-based development - Small, frequent merges prevent integration hell

The reality is that most coordination problems stem from poor communication and unclear ownership—problems that microservices don't magically solve. If your teams can't agree on who owns what in a monolith, they're going to have the same fights about API contracts between services.

Overhead​

When you break down services into tiny pieces, you expand the breadth of services that must be maintained. With that breadth comes the depth of optimizing memory allocation, upgrading packages, tweaking replica sets, setting alerts, and more. If we go one level above the infrastructure, we also create the overhead of ensuring that each microservice doesn't re-implement something that another microservice has—which requires someone who has context and knowledge of the entire fleet.

Let's enumerate the hidden costs:

  1. Infrastructure complexity - Each service needs its own CI/CD pipeline, monitoring, logging, and alerting. Multiply that by 20 services and you've got a full-time job just keeping the lights on.

  2. Network latency - What was a function call is now an HTTP request. What was microseconds is now milliseconds. Death by a thousand round trips is real.

  3. Distributed debugging - Good luck tracing a bug across 7 services with different log formats, time zones, and retention policies. Yes, distributed tracing helps, but it's yet another thing to set up and maintain.

  4. Data consistency - Transactions that span multiple services require sagas, eventual consistency patterns, and a PhD in distributed systems to get right.

  5. Dependency management - Service A depends on Service B which depends on Service C. One breaking change and you're playing dependency whack-a-mole across your entire fleet.

  6. Cognitive load - Engineers need to understand not just their service, but how it interacts with a constellation of other services. The mental model required to debug issues grows exponentially.

When Microservices Actually Make Sense​

I'm not saying microservices are always wrong. They genuinely shine when:

  • Different scaling requirements - Your image processing service needs GPUs and 10x the compute of your user auth service
  • Different technology requirements - Some problems genuinely benefit from different languages/runtimes
  • Organizational scale - You have 100+ engineers and coordination costs in a monolith become prohibitive
  • Isolation requirements - Regulatory or security requirements demand hard boundaries between systems
  • Third-party integration - You're building a platform where external teams need to deploy independently

But notice that most of these are scale problems. If you're not at that scale, you're paying the microservices tax without getting the benefits.

The Modular Monolith: Best of Both Worlds​

Here's the secret the industry doesn't talk about enough: you can have your cake and eat it too.

A modular monolith gives you:

  • Clear boundaries between modules (like microservices)
  • Shared infrastructure and deployment (like a monolith)
  • The ability to extract services later when you actually need to

Structure your monolith with strict module boundaries, enforce them with linting rules and architecture tests, and you get 80% of the organizational benefits of microservices with 20% of the operational overhead.

The best part? When you do need to extract a service (because that one module genuinely needs different scaling), you've already done the hard work of defining the boundaries. The extraction becomes a mechanical exercise rather than an archaeological expedition.

Conclusion​

The microservices movement solved real problems at companies operating at unprecedented scale. But somewhere along the way, the industry cargo-culted these patterns into organizations where they create more problems than they solve.

Before reaching for microservices, ask yourself:

  • Do we have a scaling problem that can't be solved by vertical scaling or read replicas?
  • Do we have a team coordination problem that can't be solved by better processes?
  • Do we have genuine isolation requirements?

If the answer to all three is "no," you probably don't need microservices. You need a well-structured monolith with clear ownership, good testing, and engineers who take pride in keeping the codebase clean.

Build the monolith. Keep it modular. Extract services when—and only when—you have evidence that you need them. Your on-call rotation will thank you.