Modular Monolith: Enforce Boundaries Inside One Deployable
Operate a modular monolith with public contracts, data ownership, and dependency guardrails.
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_attemptsDirect 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
- Microsoft Learn — https://learn.microsoft.com/en-us/shows/on-dotnet/on-dotnet-live-modular-monoliths-with-aspnet-core
- Martin Fowler, Monolith First — https://martinfowler.com/bliki/MonolithFirst.html
Monolith Architecture: One Deployment Boundary, Many Possible DesignsNew
Reason about monolithic architecture through deployment boundaries, in-process collaboration, shared transactions, scaling, release coupling, failure blast radius, internal modularity, team ownership, and decomposition signals.
Microservices: Independent Deployment Boundaries
Reason about microservices through deployment autonomy, business capabilities, data ownership, distributed failure, contracts, consistency, and operations.