Architecture · Backend

A modular monolith before microservices: defining real boundaries

Design modules around business ownership and explicit contracts before adding distributed operations.

TOPIC HUBAPIs, SaaS & System Architecture
Distinct rooms within one building, illustrating modular software boundaries.
An editorial interpretation of the topic, followed by a practical execution diagram.

One application does not require every component to know every other component’s internals. Many services do not automatically create good boundaries either. A modular monolith can offer one deployment with explicit business ownership and contracts. It is a deliberate design approach, not something achieved merely by creating folders.

Start with business ownership

A membership product contains plans, subscriptions, payments and benefits. Technical folders named controllers and services do not tell you who decides that a membership is active or who verifies a successful payment. Assign those decisions to modules before choosing dependencies.

Define a public contract

Memberships can consume a verified payment result without editing payment records directly. A payment adapter should not understand every plan’s benefit rules. NestJS modules organize controllers and providers and expose selected providers through exports. That mechanism supports boundaries, but the business design must still define them.

Payments -> PaymentConfirmed contract -> Memberships
Memberships -> EntitlementGranted contract -> Benefits
Notifications consumes outcomes; it does not decide eligibility.

Separate decisions from side effects

Activating a membership is a business transition. Sending a welcome message is a side effect. A mail outage should not undo a valid payment or leave eligibility ambiguous. Persist the transition and deliver notifications through a retryable path. Where delivery must survive a crash, use a durable event record rather than only an in-memory callback.

Explicit contracts separate decisions even within one deployment.
Explicit contracts separate decisions even within one deployment. Open for a larger view

Address circular dependencies

If orders import payment internals and payments import order internals, review ownership. A small orchestration layer can coordinate public contracts without either module owning the other. A large shared folder often relocates coupling rather than solving it. Share stable contracts and genuine utilities, not every convenient business helper.

Test the boundaries

Test through public interfaces: one confirmed payment grants one entitlement, and a notification failure leaves that decision intact. Where supported, enforce import restrictions on internal module files. Watch how many modules a routine change touches; broad edits may reveal misplaced responsibilities.

Extract services for measured reasons

Independent scaling, team ownership or a specific failure-isolation need can justify extraction. Include networking, authorization, tracing, contract compatibility and deployment coordination in the cost. Good modular boundaries create an option to split later; they do not require doing so. Keep the architecture proportional to the product and the people operating it.

Scenario: adding benefits to a membership plan

Changing plan benefits should not require editing the payment adapter. Plans describe benefits, memberships determine entitlement, and benefit consumption enforces usage rules. Where the product must honor historical terms, keep the relevant subscription terms instead of always reading today’s plan. Resolve that business decision before translating relationships into service calls.

An early warning about weak boundaries

Watch ordinary feature work. If adding a display field requires changes to payments, notifications and membership rules, a shared object may expose too much internal detail. Reduce the contract to what its consumer genuinely needs. Judge modularity by which decisions can change safely without understanding unrelated internals, not by the number of folders.

Official references

These references document the tools discussed. Examples and design decisions are illustrative and should be adapted to the project and its versions.

Prepared by: Noor Yasser

FROM DECISION TO DELIVERY

Working through a similar engineering challenge?

I help teams turn architecture decisions into a clear scope and dependable, reviewable implementation.

Book a 30-minute callRelated serviceSaaS & digital product developmentRelevant projectMember Plus