Skip to content

Architecture

Modular monolith vs microservices: what to build first

What a modular monolith is, how it compares with microservices on deployment, data, team size and failure modes, and the signs that tell you when to split.

By · Published · 3 min read

Short answer: start with a modular monolith unless you have a concrete reason not to. It is one deployable application with strict internal boundaries between modules. You get simple deployment, easy transactions and fast development, and you keep the option to extract a service later. Microservices solve organisational and scaling problems that most small teams do not yet have.

What is a modular monolith?

A single codebase, built and deployed as one unit, divided into modules that each own a part of the business: billing, inventory, accounts, users. The rule that makes it "modular" is that modules talk to each other only through defined interfaces, and each owns its tables. Billing does not reach into inventory's tables. It calls an inventory function.

A monolith without that discipline is a ball of mud. The structure is the whole point.

What are microservices?

Independently deployed services, each with its own data store, communicating over the network by HTTP, gRPC or messages. Each team can build, release and scale its service on its own schedule.

How do they compare?

  • Deployment: monolith, one artifact and one pipeline. Microservices, many pipelines and versions that must stay compatible.
  • Transactions: monolith, a database transaction covers a whole business operation. Microservices need sagas or eventual consistency, and failure handling gets hard.
  • Debugging: monolith, one stack trace. Microservices, distributed tracing across hops.
  • Scaling: monolith scales as a whole, horizontally if stateless. Microservices scale hot parts independently.
  • Team independence: monolith, merge conflicts and shared release train. Microservices let teams ship alone, at the cost of coordination overhead on interfaces.
  • Failure modes: monolith, a bug can take everything down. Microservices, partial failure, timeouts and cascading retries.
  • Operations cost: monolith is cheap. Microservices need service discovery, observability, secrets, and often an orchestrator.

What goes wrong with microservices too early?

A small team ends up running a distributed system with all its failure modes before it knows where the real boundaries are. Boundaries drawn on day one are guesses. Moving a boundary inside a monolith is a refactor. Moving one between services is a migration with data copy and a coordination plan.

A sign of trouble is a "distributed monolith": services that must be deployed together, share a database, or call each other synchronously in long chains. You pay the cost of both models and get the benefits of neither.

When does splitting make sense?

  • Different parts need very different scaling or hardware, such as a video encoder next to a CRUD app.
  • Teams are big enough that coordinating one release is the bottleneck.
  • A component needs a different language or runtime for a real reason.
  • A part needs different availability or security isolation, such as payment handling.
  • A module has stable, narrow boundaries and its own data.

How do you keep a monolith modular?

  • One folder or package per module, with a small public interface file.
  • Enforce boundaries in CI. Go has internal/ packages, Java has module systems and ArchUnit, TypeScript has lint rules for import paths.
  • Each module owns its tables. Others access data through the module's API, not by joining across.
  • Use in-process events for decoupling, so a later extraction only changes the transport.
  • Avoid shared "utils" that become a dumping ground.

How did I decide for my own products?

My business systems, such as Rechvix, are single deployables with a PostgreSQL database, one runtime and clear package boundaries. That choice matches how they are installed: on a customer's own server, by people who do not want to run ten containers. For a self-hosted product, fewer moving parts is a feature. If you do run containers, Docker Compose is usually plenty, and you may not need Kubernetes at all.

References

Author

Raktim Ranjit is a software engineer and the founder of NodeDR Infotech. He builds and maintains the software described here.

Have something in mind?

Let’s build something useful.

Tell me about the idea, product, or workflow you’re working through.

Tap to say hello