Architecture Decision Record: A Modular Monolith Before Microservices
A reference architecture decision record for choosing a modular monolith, enforcing module boundaries and identifying when service extraction is justified.
On this page +
Status: Proposed reference decision. This record illustrates an architectural choice for an early B2B product. It is not a statement that BRIVOX applies this architecture to every project or has deployed this example for a client.
Context#
The assumed product has a small engineering team, closely related workflows and no demonstrated need to release or scale each business capability independently. The team needs clear ownership and reliable delivery while its understanding of the domain is still changing.
The decision concerns deployment boundaries. It does not remove the need for internal module boundaries, access control or observable operations.
Decision#
Begin with one deployable application organized around business modules. For example, identity and membership, scheduling, billing and notifications each expose a deliberate interface. Internal details stay behind that interface.
A module should not casually read another module's tables just because both use the same database. Document which module owns each business invariant and which interface may change it. Review dependency direction during implementation.
Keep long-running work outside the interactive request where appropriate. A background worker can still belong to the same product and codebase; asynchronous execution does not require every capability to become a separate service.
Alternatives considered#
A loosely structured single application makes initial changes easy but leaves ownership and coupling implicit. That weakens future changes and makes extraction harder.
Microservices can support independent deployment and scaling, but introduce distributed communication, consistency and operational concerns. Microsoft's architecture guidance describes these trade-offs. Those costs need a concrete reason, not an assumed future traffic level.
Separate services may be appropriate immediately where security boundaries, an existing platform contract or independent teams require them. The proposed decision does not override those constraints.
Consequences#
The initial system has a coordinated deployment and a shared failure surface. Module discipline must be enforced through code review and dependency rules; a folder name alone creates no boundary.
In return, local development, tracing a business transaction and changing related features can remain comparatively direct. This is a design expectation for the scenario, not a measured productivity claim.
Define module-level logs and metrics early enough to understand where time and failure accumulate. Avoid putting sensitive business payloads into those logs.
Validation and reconsideration#
Review a change that crosses two modules and verify it uses the intended interfaces. Check whether one module can be tested without constructing unrelated business state. Track dependencies that make routine changes unexpectedly broad.
Reconsider extraction when a specific module needs independent releases, distinct resource scaling, stronger fault isolation or separate team ownership. Before extracting it, define its data ownership, compatibility strategy, failure behavior and on-call responsibility.
The handover should include a module map, key interfaces and the assumptions behind this decision. BRIVOX's SaaS development and Cloud & DevOps services can help assess those boundaries for an actual product.
Technical reference#
Microsoft Azure Architecture Center: microservices architecture style.