Skip to content

Modular monolith

A modular monolith is one application, deployed as one unit, whose code is divided into modules along business lines (orders, billing, catalog). Each module hides its internals and exposes a small, explicit interface. Other modules may use only that interface.

It aims for most of the organizational benefits of microservices without the cost of running a distributed system.

flowchart TB
    api[API and UI] --> orders & billing & catalog
    subgraph app [One deployable application]
        orders[Orders module]
        billing[Billing module]
        catalog[Catalog module]
        orders -- public interface --> billing
        orders -- public interface --> catalog
    end
    orders --> s1[(orders schema)]
    billing --> s2[(billing schema)]
    catalog --> s3[(catalog schema)]
  • Modules follow business capabilities. Each module owns one area of the domain, end to end.
  • Explicit public interfaces. Modules call each other only through published APIs, never through internal classes.
  • Data ownership per module. Each module has its own tables or schema. Other modules don’t query them directly.
  • Boundaries enforced by tooling. Build rules, architecture tests or language-level module systems make it fail the build when a module reaches into another’s internals.
  • Events inside the process. Modules can communicate through in-process events to keep coupling low.
  • Simple operations: one deployment, one pipeline, one set of dashboards.
  • Fast, reliable communication: in-process calls don’t fail like network calls do.
  • Ordinary transactions: consistency across modules can use one database transaction when truly needed.
  • Cheap to restructure: moving a boundary is a refactor, not a migration.
  • A path to microservices: a well-isolated module can later be extracted into a service.
  • Scales as one unit: you can’t scale a single busy module on its own.
  • Shared release train: all teams deploy together, so one team’s bug can block another’s release.
  • Boundaries erode without enforcement: shortcuts between modules are always one import away.
  • One technology stack: all modules share a language and runtime.
  • Most new products, especially while the domain is still being discovered.
  • Small to medium organizations with one to a few teams.
  • Systems that need strong consistency across business areas.
  • Many teams are blocked by a shared release process.
  • Parts of the system have very different scaling, availability or technology needs.

See Microservices vs modular monolith for a full comparison.

  • Modules by layer instead of by business. A “services module” and a “repositories module” isn’t a modular monolith; it’s a layered architecture.
  • Shared tables. If two modules write to the same table, they aren’t separate modules.
  • No automated boundary checks. Rules that only live in a wiki will be broken within months.

Glossary: bounded context, coupling

  • Simon Brown, “Modular monoliths” (talk, available online)
  • Sam Newman, Monolith to Microservices

Written and edited by Abhinav Taduka, enterprise software architect.