Published
- 4 min read
Modular monolith: The 1 architectural pattern most devs ignore

Shock.
That’s the word I could use to describe how the complexity of real-world apps hits you right after college.
At my first job, I worked on a huge monolith app.
10+ projects.
Several different layers.
Features that talk to each other.
All that leads to code that is more intimate than a fresh couple on Valentine’s Day.
Next app, same. Huge monolith full of spaghetti code.
Next app, same.
So, what teams do to try to decouple this mess?
They reach for microservices.
Microservices promise you’ll have components that are independent and small. So there is no more tight coupling. Which is fine.
But there are 2 major issues you now have:
- Increased complexity - Separate services require more orchestration, time, and effort to develop, deploy, and manage in production.
- Distributed monolith - Service separation is hard to get right. Even if you put features in different services, that doesn’t magically mean your coupling problems are gone. For example, if you have a service A, but it heavily relies on service B and service C, and it cannot function when one of those services is down, your services are not split properly. So you still have coupling. But you’ve also replaced direct method calls between classes with network calls.
So, if monoliths are a nightmare to work with, and microservices can turn into a complex beast, is there a middle ground?
Yes. And it’s called modular monolith architecture.
What is a modular monolith?
Modular monolith is a software architectural style where features are split into well-defined modules within a single deployment unit.
One of the fundamental principles of this architectural style is high cohesion. For example, in an e-commerce application, you would have a separate module for:
- Handling orders
- Inventory management
- Processing payments, etc.
All modules are part of a single system, run in the same process, and can share the same database (more on the database later).
But they follow strict boundaries.
The code of each module is separate from the other modules. The goal of modular monolith is to balance the simplicity of monoliths with the maintainability advantages of microservices.
Monolith vs Modular Monolith vs Microservices
The best way to compare these 3 architectural styles is to compare them side by side:
Feature | Monolith | Modular Monolith | Microservices |
---|---|---|---|
Deployment | Single unit | Single unit | Multiple units |
Boundaries | Often blurred | Strict & enforced | Fully isolated |
Primary Scaling Mechanism | Vertical | Vertical (optionally horizontally later) | Horizontal |
Dev Complexity | Low | Moderate | High |
Operational Overhead | Low | Low | High |
Best For | Simple apps | Growing apps | Large complex systems |
Practical implementation of modular monolith - structure, communication, and data isolation
There is a lot more to say about practical implementation than I can cover in a single section, but here is the birds-eye overview of the modular monolith.
How to structure the solution and projects
At a high level, do this:
- Start by creating a blank solution.
- Add a Web project. This is the entry to your system. And glue that holds all the modules together.
- Create a solution folder and put your module code there. The module can be separated into several projects. You can also put your module test projects here.
- For shared code, create a separate project. This can be named SharedKernel, Common, Shared, or anything else. But keep this project thin. It should only contain classes that are independent of all modules. Think Result, PagedResponseDto, or other similar utility classes.
Communication between modules
Sooner or later, one module will have to get data from another. For that, there are several approaches you can take:
- Synchronous ways to call another module - direct calls, calls via mediator, separate Contracts project, etc.
- Asynchronous ways to call another module - using message queues.
Isolating data
For storing and isolating data, you have the following options:
- Same database, same schema - simple, but can couple tables between modules.
- Same database, different schema - often preferred choice. Each module stores data in a single database, but they use different schemas.
- Different databases per module - each module has its own database. You have isolation at the data layer, but now you need to take care of additional databases, data consistency, etc.
Overall, modular monolith represents a great option when you have a complex application with many developers working with it.
Every Friday I share actionable .NET advice, insights, and tips to learn the latest .NET concepts, frameworks, and libraries inside my FREE newsletter.
Join here 9,100+ other developers