Why: the goal or problem
Imagine a hiking app where walkers save guides and buy extras. Weekend tags risk changing billing code. The team wants clear ownership within one release, without separate services.
How: work toward a solution
- One team ships Catalog, Library and Billing together; saved Hiking Guide has no tag.
- Add tags to Library-owned tables; deploy app v2 with unchanged Billing. One database; cross-module table access is forbidden.
- Library calls Catalog’s API in-process, then writes
weekend. Failed lookup leaves no tag; retry after recovery.
Illustrative example
Internal contracts, shared release
Hiking app · one team · Hiking Guide has no weekend tag
Change: add a Library tag; Billing behavior stays unchanged.
Deployment unit · 1
App v1 → App v2Catalog
APIArticle lookupOwned internalsCatalog-owned tablesLibrary
Tag feature addedAPISet Hiking Guide tag: weekendOwned internalsLibrary-owned tables + tag fieldBilling
APIBehavior unchangedOwned internalsBilling-owned tables
Library → Catalog API · In-process call
No direct access to another module's tables. Calls enter through its API.
One shared database; separate table ownership. Library changes its storage inside the common release.
- Lookup succeeds → write weekend → Hiking Guide has tag weekend.
- Lookup fails before writing → no tag. Report failure; retry after recovery.
A monolith subtype: one release and shared process failures. Enforce API boundaries with code rules and tests; folders alone cannot protect them.
Ownership boxes describe access rules, not database-machine counts.
Module APIs protect source and data ownership. They still share this release and process failure boundary.
What: the concept
A modular monolith combines one deployment with deliberate internal boundaries. Module APIs protect owned internals. It is still a monolith. Fowler
Enforce boundaries beyond folders; releases and process failures remain shared. Modules can use hexagonal ports.
Discuss this idea
Comments are shared across languages. GitHub login required to post.