A lot of teams talk about monoliths vs microservices as if the deployment model is the whole story.
It isn’t.
What matters much earlier is whether your system has real internal boundaries.
That’s why I think the distinction between a regular monolith and a modular monolith is so useful. Both are still a single deployment unit. Both can be clean. Both can be well-structured. But a modular monolith is stricter about one thing that becomes existential as a system grows:
who is allowed to know what, and how they are allowed to know it.
In a normal monolith, you can absolutely start with good intentions. Nice folders. Clean Architecture. Separate layers. Feature organization. Everything looks tidy in year one.
Then reality shows up.
A handler in one area reaches into another domain “just for now.” A query joins across tables because it’s convenient. One team reuses another team’s entity because it saves a little time. None of these decisions feel catastrophic in isolation.
But I’ve seen this movie enough times to know how it ends: the codebase still compiles, still ships, and still gets more expensive to change.
That’s the core problem. Coupling doesn’t usually arrive as a dramatic architectural mistake. It sneaks in through convenience.
A modular monolith is an attempt to put guardrails around that tendency.
What I like about the model is that it forces a more honest definition of a module. A module is not just a folder. It’s not a naming convention. It’s not a section in the repo that everybody politely agrees not to touch.
A real module has:
- clear ownership
- internal implementation details
- a public contract
- controlled touchpoints with the rest of the system
That shift matters.
Once teams are required to go through a module’s public API instead of reaching directly into its internals, the architecture gets more intentional. You stop leaking entities across the system. You stop creating accidental dependencies that nobody meant to design. You start making coupling visible.
And visible coupling is manageable coupling.
I also like the database angle here, because this is where a lot of otherwise “clean” monoliths quietly fall apart.
At the application layer, teams often talk about boundaries. At the database layer, they ignore them completely. Shared tables, cross-schema joins, direct reads into another domain’s data — all of it works, until one day it doesn’t.
Database coupling is some of the hardest coupling to unwind because it gets normalized. It feels efficient. It feels pragmatic. And then later it becomes the reason nothing can move independently.
That’s why schema or persistence isolation inside a modular monolith is more than a technical nicety. It reinforces the same principle as the code structure: access should be intentional, not incidental.
Now, I don’t think this means every monolith needs the full modular monolith treatment on day one.
In fact, I’d be cautious about over-engineering too early. Strong boundaries come with upfront cost. You’re creating more explicit seams, more contracts, more discipline. If the product is still searching for basic fit, that may be more ceremony than value.
But once the system starts growing, once multiple teams are involved, once the business domains begin to stabilize, those boundaries stop feeling theoretical. They become leverage.
That’s the real strategic benefit for me.
A modular monolith gives you many of the advantages people chase with microservices — clearer ownership, better isolation, easier extraction later — without immediately paying the tax of distributed systems.
And that tax is real.
I’ve watched plenty of organizations adopt microservices when what they actually needed was better modularity. They thought the answer was network boundaries. The real problem was they never established architectural boundaries in the first place.
If your internals are tangled, splitting the deployment just spreads the tangle across the network.
So when I look at monolith vs modular monolith, I don’t see a religious debate. I see a maturity question:
Are we serious about boundaries, or are we just hoping folder structure will save us?
For most teams, a well-designed modular monolith is a very strong answer. It keeps operational complexity low while forcing architectural discipline where it matters most.
And if you ever do need to extract a module into its own service later, you’re not starting from chaos. You’re starting from a system that already learned how to separate concerns.
That’s a much better place to be.