The monolith vs. microservices debate is a great way to waste six months of an early-stage company's engineering time. It is the wrong question. And yet it's one of the first architectural conversations most founders end up having.

Here's why it's the wrong question, and what the right question actually is.

Diagram comparing a structured monolith with clear domain boundaries versus prematurely split microservices with scattered, tangled connections

The Debate's Origin Story

The argument for microservices comes from large organisations — Netflix, Uber, Amazon — that had specific problems: teams that needed to deploy independently, domains that had genuinely diverged, scaling requirements that varied enormously by service. They moved to microservices because they had the team size, the domain complexity, and the operational sophistication to manage the overhead.

Then every startup with a twelve-page pitch deck decided they needed the same architecture.

This is cargo cult thinking. You're adopting the solution without having the problem.

Conway's Law Is Not Optional

Melvin Conway observed in 1967 that organisations design systems that mirror their communication structure. If you have one team, you'll build one system. If you have five teams, you'll build five systems — whether you intend to or not.

This is not a guideline. It's closer to a law of nature.

The practical implication: if you're a ten-person company with three engineers, your architecture should match your team structure. A well-organised monolith with clear module boundaries will serve you better than a distributed system you don't have the people to operate.

"Microservices aren't free. Every one of those costs is paid in engineering time. When you're small, that time is the one thing you don't have."

Microservices come with operational overhead: service discovery, distributed tracing, network latency, deployment coordination, data consistency across service boundaries. Every one of those costs is paid in engineering time. When you're small, that time is the one thing you don't have.

What We Actually Look For

When we inherit a codebase, we're not asking "monolith or microservices?" We're asking: where are the domain boundaries?

A domain boundary is a place where two parts of your system have fundamentally different concerns, different rate-of-change requirements, or different teams responsible for them. Authentication is a domain. Billing is a domain. The core product workflow is a domain.

Inside those boundaries, the code should be deeply cohesive. Across them, the coupling should be loose and explicit. Whether those boundaries are enforced by separate services or by module separation within a monolith is a deployment detail. It matters, but it's downstream of the domain question.

The Practical Path

For almost every product we've worked on, the right starting point is a monolith with disciplined modules. Not a big ball of mud — a structured monolith where domain boundaries are enforced by folder structure, clear interfaces, and code review discipline.

When a module grows large enough, stable enough, and distinct enough — and when the team operating it is separate enough — then you extract it. Not before.

The test is simple: can you draw a clear line around this part of the system and say "a separate team could own this, and the rest of the product wouldn't care"? If yes, extraction is on the table. If no, you're not splitting a service — you're splitting a mess.

We've rebuilt systems that were prematurely split into microservices. It's expensive, demoralising, and almost always traceable to an early architectural decision made to impress investors rather than serve engineers.

Start with the domain. The deployment model will follow.

See how we approach architecture decisions →
← Back to Blog