Spring Modulith: Building Modular Applications with Spring Boot

Spring Modulith Modular Application Guide

Spring Modulith modular architecture enables you to build well-structured monolithic applications with clear module boundaries enforced at compile time. Therefore, you get the simplicity of a monolith with the modularity benefits typically associated with microservices. This guide covers practical implementation patterns for production applications.

The Case for Modular Monoliths

Microservices introduce distributed system complexity including network failures, data consistency challenges, and operational overhead. Moreover, most teams adopt microservices prematurely before understanding their domain boundaries. As a result, they end up with a distributed monolith that combines the worst of both approaches.

In contrast, a modular monolith runs as a single deployment unit while maintaining strict internal boundaries. Consequently, refactoring is simpler and you can extract modules into services later when the boundaries are well understood.

Spring Boot modular application code structure
Modular application structure with clear package boundaries

Defining Module Boundaries with Spring Modulith

Spring Modulith uses package conventions to define modules. Additionally, each top-level package under your application base package becomes a module with its own public API:

// Module structure
com.example.app/
├── order/                    // Order module
│   ├── OrderService.java     // Public API
│   ├── Order.java
│   └── internal/             // Hidden from other modules
│       ├── OrderProcessor.java
│       └── OrderValidator.java
├── inventory/                // Inventory module
│   ├── InventoryService.java
│   └── internal/
│       └── StockCalculator.java
└── shipping/                 // Shipping module
    ├── ShippingService.java
    └── internal/
        └── CarrierClient.java

Classes in the internal package are invisible to other modules. Therefore, Spring Modulith enforces encapsulation that plain Java packages cannot guarantee.

Event-Based Module Communication

Modules communicate through Spring application events rather than direct method calls. Furthermore, this decoupling enables modules to evolve independently. However, synchronous events still execute within the same transaction for consistency.

For example, when an order is placed, the order module publishes an OrderPlaced event. Meanwhile, inventory and shipping modules listen and react without direct dependencies on the order module.

Software development with event-driven architecture
Event-driven communication between application modules

Spring Modulith Modular Testing

Module tests verify that each module works correctly in isolation. Specifically, the @ApplicationModuleTest annotation bootstraps only the module under test with its dependencies. As a result, tests are faster and failures point directly to the affected module.

Additionally, architecture tests validate module dependency rules at build time. Consequently, accidental coupling between modules fails the build before it reaches production.

Documentation and Observability

Spring Modulith generates module documentation including dependency diagrams and event catalogs automatically. Moreover, it integrates with Actuator to expose module health endpoints. Therefore, operations teams can monitor module boundaries in production and detect architecture drift.

Developer workspace with module documentation
Auto-generated module documentation and dependency visualization

Related Reading:

Further Resources:

In conclusion, Spring Modulith modular architecture bridges the gap between monoliths and microservices by enforcing clean boundaries within a single deployment. Therefore, start with a modular monolith and extract services only when domain boundaries are proven.

Scroll to Top