The problem
Teams jump to microservices to get boundaries, but they also inherit network failures, distributed transactions, and N pipelines to maintain. Most of the value came from the boundaries, not the network hops.
How it works
Rules that make it modular rather than a "big ball of mud":
- Each module exposes a small public API. Everything else is internal, enforced by lint rules, package boundaries, or tools like
dependency-cruiseror ArchUnit. - Each module owns its data (its own schema or collections). No cross-module joins.
- Modules talk synchronously through the public API, or asynchronously through in-process events.
- Any module can later be extracted into a service without a rewrite.
- New products where domain boundaries are still moving
- One team or a few teams
- You want fast refactoring and one transaction boundary
- Modules need very different scaling or runtimes (GPU vs CRUD)
- Many teams need fully independent release cadences
Trade-offs
- ✅ One deploy, one debugger, local transactions, simple ops.
- ✅ Keeps the option to extract services later, with boundaries already proven.
- ❌ Boundaries erode unless they're enforced by tooling.
- ❌ It all scales together, and one bad module can take down the process.
For the 15-module field-sales CRM, the design direction is a modular monolith: one Next.js/Node deployable, with each module owning its collections and exposing a service interface. Extraction stays possible, but nobody pays microservice costs on day one.
Sources & further learning
Videos, courses, docs and books I recommend for this topic.
Related topics
Microservices Architecture
Structure a system as independently deployable services, each owning a business capability and its data, communicating over the network.
Coupling, Cohesion & Separation of Concerns
High cohesion inside a module, loose coupling between modules — the single most important property of a maintainable architecture.
Strangler Fig Migration
Replace a legacy system incrementally — route traffic slice by slice to the new system behind a facade until the old one can be switched off.