Can Modular Monoliths Outperform Microservices? Exploring Spring Modulith
This article examines how modern modular monoliths, especially Spring Modulith, can provide scalable, low‑overhead alternatives to microservices by isolating modules, reducing remote calls, and simplifying deployment while addressing common concerns about complexity and performance.
Modern modular monoliths (and Moduliths) are redefining monolithic architecture, offering a hybrid approach that combines the best of both worlds.
Historically, ideas cycle back; what was once discarded often returns stronger. Recently, relational databases have resurged, and monoliths are poised for a comeback, while microservices and serverless are largely driven by cloud vendors seeking more resource sales.
For most use cases, microservices provide limited financial benefit, and scaling them merely distributes costs. A recent technical group discussion highlighted that monoliths, even at massive scale (e.g., Amazon, eBay), face challenges when refactoring large codebases, but they remain a viable option.
Modular Architecture
Developers interested in the next step should explore the Spring Modulith project, which enables building a cohesive system from dynamically isolated modules. This approach separates testing, development, documentation, and dependencies, aiding microservice‑style isolation with minimal overhead.
It eliminates remote calls and duplicated functionality (storage, authentication, etc.). Spring Modulith does not rely on Java Platform Module System (Jigsaw); instead, it enforces separation at test and runtime within a standard Spring Boot project, offering additional observability features.
Example Package Structure
Traditional Spring monolith packages:
com.debugagent.myapp</code>
<code>com.debugagent.myapp.services</code>
<code>com.debugagent.myapp.db</code>
<code>com.debugagent.myapp.restWith Modulith, the structure becomes more domain‑oriented:
com.debugagent.myapp.customers</code>
<code>com.debugagent.myapp.customers.services</code>
<code>com.debugagent.myapp.customers.db</code>
<code>com.debugagent.myapp.customers.rest</code>
<code>com.debugagent.myapp.invoicing</code>
<code>com.debugagent.myapp.invoicing.services</code>
<code>com.debugagent.myapp.invoicing.db</code>
<code>com.debugagent.myapp.invoicing.rest</code>
<code>com.debugagent.myapp.hr</code>
<code>com.debugagent.myapp.hr.services</code>
<code>com.debugagent.myapp.hr.db</code>
<code>com.debugagent.myapp.hr.restThis layout mirrors microservice boundaries while keeping a single deployable unit, allowing teams to focus on isolated domains without stepping on each other's toes.
Modules can be annotated to enforce one‑way dependencies (e.g., HR should not depend on invoicing). Events provide fast, transactional decoupling between modules.
Although some microservice tooling (feature flags, messaging) remains applicable, Spring Modulith simplifies deployment and observability, often requiring less infrastructure than full microservice stacks.
Scalability and Performance
Scaling a monolith can be simpler than scaling equivalent microservices because there is only one running instance to replicate. Performance tools can profile the entire system, and fine‑grained caching can eliminate 80‑90% of read I/O, reducing network overhead.
Kubernetes can still be used with monoliths; container images may be larger, but tools like GraalVM mitigate size concerns.
Bottlenecks
Typical monolith bottlenecks include the database, as a single DB can become a performance choke point. However, modern clustering, distributed caches, and specialized databases (e.g., Redis, time‑series stores) can alleviate these limits.
Benefits
Monoliths allow transactions without eventual consistency, simplifying debugging and reducing the complexity of distributed tracing. Network overhead is minimized, and the overall system remains easier to understand and test.
Why Use Microservices?
Microservices gained popularity alongside languages like Python and JavaScript, offering fine‑grained cost control and rapid scaling via Kubernetes. They also enable independent team ownership but can foster siloed development and increased overall system complexity.
Starting with a Monolith
Many experts recommend beginning with a monolith and refactoring to microservices only when necessary. A modular monolith provides a balanced approach, delivering the benefits of isolation without the operational overhead of a full microservice architecture.
For further reading, see the original article by Shai Almog.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
