New33 new system architecture lessons added!Explore What's New →
Software Development Atlas
Software Architecture

Modular Monolith: Enforce Boundaries Inside One Deployable

Operate a modular monolith with public contracts, data ownership, and dependency guardrails.

EvolvingVerified Sep 11, 2026Review target: 180 days
Edit on GitHub

Personal learning atlas by Tran Trong Thuc · About this Atlas · Atlas last updated Sep 10, 2026

Modular Monolith: Enforce Boundaries Inside One Deployable

A modular monolith keeps one deployable application while enforcing internal module ownership.

Enforce dependency direction

Use public entry points, forbid deep imports, and make dependency cycles fail an architecture test or import rule.

Orders owns: orders, order_lines
Billing owns: invoices, payment_attempts

Direct database access or cross-module queries bypass owner invariants. Prefer a public operation or intentional read model.

Calls, events, and transactions

An in-process function call is appropriate when the caller needs an immediate answer.

Events still have contracts for semantics, ordering, duplicates, and freshness. A shared database can support a local transaction across modules, but the boundary needs a named owner.

A module boundary improves change locality; it does not provide process-level fault isolation or independent scaling.

Extract to a microservice only when independent deployment brings concrete scaling, security, fault-isolation, or release-cadence value.

Production scenario

Orders imports Billing ORM entities, Billing queries Orders tables directly, and a shared core package owns business rules.

Impact: small features require broad coordination and future service extraction would move hidden coupling across the network.

Root cause: package names exist without enforced public contracts, private internals, dependency direction, or data ownership.

Correct pattern: assign capability owners, forbid deep imports, route cross-module reads/writes through explicit contracts, assign table/schema ownership, break cycles, and enforce the dependency graph with architecture tests.

Self-check: must every module be independently deployable?

No. A modular monolith deliberately keeps one deployment boundary. Independent deployment changes the topology toward services or microservices.

Production checklist

  • There is one understood single deployable.
  • Modules align with capabilities and ownership.
  • Public contracts are small; private internals cannot be deep-imported.
  • The dependency graph is machine-checkable.
  • Business data has module ownership even in a shared database.
  • Direct cross-module table writes are forbidden or explicit exceptions.
  • In-process calls and events are chosen by semantics.
  • Cross-module transaction boundaries have an owner.
  • Module boundaries are not confused with fault isolation.
  • Extraction requires concrete operational evidence.

Agent rule

Identify the owning module first, use its public contract, keep storage and implementation details private, and strengthen a machine-checkable boundary when a change reveals an unauthorized dependency.

Sources

On this page