The modular monolith is a decision, not a consolation prize
How to keep a single deployable system modular, and how to recognize when extraction pressure is real.
ao
Ayomide OlajideSoftware engineer
Modules communicate through explicit public contracts. Each module owns its persistence; cross-module calls do not grant direct access to another module’s data. These boundaries can exist inside one deployable.
Deployment shape is not architecture
Teams often jump from a tangled monolith to microservices because the word monolith has become shorthand for risk. A single deployable can still have strong boundaries, separate modules, and explicit integration contracts. Conversely, several services can share a database and behave like one distributed monolith.
The useful question is not “should we use microservices?” It is “which boundary needs independent deployment, scaling, ownership, or failure isolation badly enough to justify the cost?”
Make modules enforceable
Give each module a public application interface and private persistence code. Ban imports from another module’s internals. Keep cross-module writes behind commands or events. These rules can be checked with linting or dependency tests; relying on team memory is not a boundary.
Extraction pressure becomes credible when a module needs a different release cadence, has a distinct operational profile, or is owned by a team that can support its reliability independently. A service boundary that exists only to make a diagram look modern adds network failure without reducing cognitive load.
Modules communicate through explicit public contracts. Each module owns its persistence; cross-module calls do not grant direct access to another module’s data. These boundaries can exist inside one deployable.
Trade-offs
A modular monolith keeps local transactions, debugging, and deployment simple. It limits independent scaling and can create coordination around releases. Services provide isolation and autonomy but require contracts, observability, retries, and operational ownership. Neither shape removes complexity; each moves it.
Conclusion
Protect boundaries before splitting processes. The architecture should make the next change safer, not merely make the current diagram more impressive.