A modulith, or modular monolith, is one deployable application organized into domain-focused modules with deliberate boundaries. It keeps modules in one runtime, so they can usually communicate in process and coordinate more simply than separate services. Microservices make parts of the system independently deployable, but that independence comes with distributed data, network communication, and more operational complexity.
What makes an application a modulith?
A modulith is not simply a monolith with folders. It is a single application whose internal modules are intentional architectural units: each has a clear responsibility, exposes a deliberate interface, and limits access to its implementation. Modules usually map to areas of the business domain rather than technical layers such as controllers, services, or repositories.
The application still runs and deploys as one unit. Calls between modules are ordinarily in-process calls, not network requests. That preserves the operational shape of a monolith while adding structural rules that make the codebase easier to understand and change without treating the entire application as one undifferentiated block.
Modulith vs. microservices: the practical differences
| Decision axis | Modulith | Microservices |
|---|---|---|
| Deployment | One deployable application; modules share a release and runtime. | Services can be deployed independently. |
| Communication | In-process calls are the default. | Network or broker communication is normal, so latency and communication failures must be handled. |
| Transactions and data | Cross-module transactions can be simpler because modules share an application runtime. | Distributed consistency must be designed explicitly across service and data boundaries. |
| Scaling | Scale the application or its runtime instances; scaling one module independently is not the default deployment model. | Scale services independently when their workloads require it. |
| Operations and failure isolation | Fewer deployables usually mean simpler operations and local debugging; modules share the runtime. | Separate services can offer stronger runtime isolation, but require more networking, deployment, observability, and failure handling. |
| Team autonomy | Code boundaries can support ownership, but teams share a runtime and release coordination. | Sound service boundaries can provide greater deployment and technology autonomy. |
These are architectural trade-offs, not guarantees. A modular monolith can have strong internal boundaries but cannot provide the same independent release cadence as separately deployed services. Conversely, splitting an application into services does not automatically create useful team autonomy: that depends on having boundaries teams can own and operate.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
When a modulith is the better starting point
Choose a modulith when a single deployment and straightforward coordination are useful, but the application needs stronger domain boundaries than a conventional monolith provides. It can be a good fit when the product or domain is still evolving, when modules need to coordinate frequently, or when there is no present need to deploy or scale parts independently.
- One release is acceptable: the application can be built, tested, and deployed together.
- In-process coordination matters: related work benefits from direct calls and simpler transaction handling.
- Boundaries matter now: the codebase needs explicit module responsibilities and controlled dependencies.
- Separate services are not yet justified: independent scaling, isolation, or release schedules are not requirements that outweigh the operational cost of distributed systems.
Thoughtworks’ 2023 Technology Radar advises starting with a well-factored monolith and breaking out separately deployable units when the application reaches a scale where microservices’ benefits outweigh their additional distributed-systems complexity. AWS’s Well-Architected Framework similarly says a monolith should remain modular so it can evolve toward SOA or microservices as product adoption grows. Both recommendations favor keeping future options open, not promising that every module will eventually become a service.
Rank #2
When microservices are worth their cost
Microservices are appropriate when independent operation is a current requirement, rather than a speculative future benefit. They can make sense when a part of the system must be released or scaled on its own, when stronger fault or security isolation is needed, or when teams need meaningful technology autonomy and can own the operational consequences.
- Independent deployment: a service needs its own release cycle without coordinating every application change.
- Independent scaling: one workload needs a different scaling profile from the rest of the application.
- Isolation: a fault or security boundary must be stronger than a module in a shared runtime can provide.
- Operational ownership: teams can manage service deployment, observability, communication, and failure handling as part of their responsibility.
Each separation turns an in-process dependency into a distributed interaction. Data ownership and consistency must be addressed across services, and callers must account for network and service failures. If these costs do not solve a concrete deployment, scaling, isolation, or autonomy problem, more services can make the system harder to operate without delivering a corresponding benefit.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
How to structure a modulith
Organize around domain modules
Spring’s introduction to application modules describes a default layout in which modules are direct subpackages of the main application package; nested packages can hold module internals. This makes the package structure reflect domain units instead of scattering one domain across application-wide technical layers.
Make module boundaries enforceable
Give each module an intentional public API and keep implementation classes inside its internals. Make dependencies between modules visible rather than allowing any package to reach into any other module’s implementation. The boundary should say what other modules may use, not merely where files happen to live.
Rank #4
Use Spring Modulith for Spring Boot applications
Spring Modulith is an opinionated toolkit for building domain-driven, modular Spring Boot applications. It can discover and verify application modules, support module-focused integration testing, observe behavior at module level, and generate documentation snippets. These capabilities help make architectural intent inspectable and testable; they do not replace the need to choose sound module responsibilities and APIs.
Spring Modulith 1.3 added nested module declarations, module-focused bootstrapping and testing, aggregated documentation, and automatic jMolecules architectural verifications when jMolecules is present. Those are version-specific additions, not a claim that every Spring Modulith version has identical capabilities.
Can you extract a modulith module as a service later?
Yes, a well-factored module can provide a credible starting point for extraction, but a package boundary alone does not make a service. Extraction changes a module-to-module call into a distributed contract and moves the problem of coordinating data and failures across a boundary.
- Validate the boundary: confirm the module owns a coherent business capability and that other modules use its public API rather than its internals.
- Establish data ownership: decide which service owns the relevant data and how other parts of the system obtain or update it. Distributed consistency must be designed rather than assumed.
- Design communication: choose how callers interact with the extracted service and how they handle communication and service failures.
- Prepare operations: make sure the service can be deployed, observed, and supported independently before relying on its separation.
If these conditions are not in place, extraction may reproduce the old coupling across a network rather than create useful independence. Keep the module in the shared application until the boundary and the operational need for separation are established.
A decision rule for choosing
Start with a modulith when one deployment and in-process coordination meet the product’s needs, while explicit domain boundaries are important. Choose microservices when independent deployment, per-service scaling, fault or security isolation, or technology autonomy is needed now and the benefit exceeds the added distributed-systems work.
Decide based on business and operational boundaries, not a target number of services. There is no authoritative numeric performance or cost figure that directly compares moduliths with microservices across applications; the trade-off depends on the system’s requirements and how well its boundaries are designed.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

