Architecture 101: Modular Monolith — A Primer

Anji…
6 min readNov 1, 2024

Microservices have emerged as a default choice for building complex, scalable, resilient, and maintainable applications. The popularity of microservice architecture has grown over the years, and it continues to be one of the most talked-about subjects in system design.

Organizations have realized that it would be highly complex to come up with the right sizing/granularity of the service when designing with microservices during the initial design stage. It also brings several challenges around development, deployment, configuration, distributed logging and tracing, and reliable communication. This is where Modular Monolith architecture got a lot of attention, and organizations are considering starting the application with Modular Monolith instead of microservices, evaluating the design, and extracting the microservices when needed.

What is a Modular Monolith?

Before delving into the modular monolith, let us understand what modularization is in system design.

Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality. A module interface expresses the elements that are provided and required by the module. The elements defined in the interface are detectable by other modules. The implementation contains the working code that corresponds to the elements declared in the interface. — Wikipedia

In summary, a module can be defined as a “logical container that groups related functionality together and makes functionality accessible via well-defined contracts.”.

Below are the characteristics of a module:

  • Must be independent and interchangeable.
  • Must contain everything necessary to serve the functionality independently.
  • Must expose well-defined contracts/interfaces for other modules to consume the functionality.

Now, let us understand what a modular monolith is.

Modular monolithic architecture is a way of organizing a software application into a set of independent modules with well-defined boundaries. These modules have ‌specific functionality, which can be independently developed and tested, while the entire application is deployed as a single unit.

Modular monolith architecture improves the cohesion of the system significantly. There may be situations where certain modules are required to be exposed as separate microservices due to various reasons like scale and load. This can be done very easily with minimal effort in modular monolith architecture.

Benefits of Modular Monolith

  • Clear Separation of Concerns: Modular monoliths use well-defined modules to encapsulate specific areas of functionality, which enforces boundaries between different parts of the application. Each module can represent a domain or subdomain, making it easier to assign ownership and maintain each part of the application.
  • Cost-effective: modular monoliths reduce the operational overhead and complexity when compared to a microservices system.
  • Improved performance: Modules communicate primarily via in-process, which reduces the network latency and improves the performance of applications.
  • Transaction Management: Transaction management in a modular monolith is easier than in a microservice ecosystem as the modules share the same database with different schema.
  • Reduced Infrastructure and Operational Complexity: Modular monoliths don’t require the extensive infrastructure that microservices need, such as a service mesh, distributed logging, and API gateways. Modular monoliths will be delivered as a single unit, greatly reducing the operational and infrastructure complexity.
  • Easier Deployment and Monitoring: Deployment remains straightforward because everything is still in a single deployment unit, with no need to manage multiple service instances, containers, or dependencies. Monitoring and debugging are also simpler than in microservices, as all logs, errors, and monitoring data are centralized within a single application instance.
  • Incremental Transition to Microservices: A modular monolith can act as a step toward a microservices architecture. As modules become more independent, they can be extracted into separate services when necessary. This gradual approach enables teams for a smoother migration without the “big bang” of a full microservices transition.

Modular Monolith Concerns

While a modular monolith has many benefits, it also has concerns and limitations.

  • Dependency Management and Modular Boundaries:
    Ensuring that each module remains independent can be challenging. Without strict enforcement, modules might become tightly coupled, leading to “spaghetti code” and dependency entanglements. Developers need to carefully design APIs and interfaces to prevent modules from directly accessing each other’s internals, which could weaken modular boundaries over time.
  • Performance Bottlenecks: Certain resource-intensive modules could become bottlenecks if they demand more resources than others, impacting the performance of the entire application. A performance issue in one module could degrade the entire system, as all modules share the same deployment environment.
  • Fault Isolation and Resilience: In a modular monolith, modules share the same process space, so if one module crashes or has a severe bug, it could bring down the entire application reducing overall system resiliency.
  • Technical Debt and Codebase Complexity: Without strict adherence to modular principles, the codebase could become difficult to maintain as modules grow and interdependencies increase, leading to technical debt. Over time, modular boundaries can erode, and the codebase could revert to a traditional monolith, where modules are highly dependent on each other.
  • Limited Scaling Options: Since a modular monolith is deployed as a single unit, it can only scale vertically (by adding more resources to a single instance) rather than horizontally (by adding more instances).
  • Limited Flexibility for Technology Diversity: Unlike microservices, where each service can use different technology stacks if needed, a modular monolith typically uses a single technology stack across all modules.

When to move to Microservices?

Transitioning from a modular monolith to a microservice-based architecture is a significant architectural shift and should be driven by specific scenarios where the benefits of microservices address current limitations or enable better alignment with business needs.

  • Scalability Bottlenecks: If certain modules are resource-intensive (CPU, memory, I/O) and need to scale independently, moving them to separate services allows tailored scaling. For example, high-traffic modules (e.g., real-time analytics) might need scaling that other modules do not.
  • Independent Deployment Requirements: If different parts of the application need frequent updates without affecting the whole system, microservices allow deploying individual services independently, reducing downtime and deployment risks. Critical services that need zero-downtime deployment or rollback capability benefit from microservices, as updates to one service can happen without affecting others.
  • Performance and Resilience Demands: If a failure in one module brings down the entire monolith, moving to microservices can isolate failures, reducing the blast radius and improving application resilience.
    Certain parts of the application may need specialized optimizations for low latency. Microservices can help by isolating these services to use faster databases, caching mechanisms, or high-performance hardware without affecting the entire monolith.
  • Organizational Scaling and Team Autonomy: When multiple teams work on different modules, microservices allow each team to own, build, deploy, and manage services independently. This decouples development and reduces inter-team dependencies, improving productivity. For organizations with cross-functional teams (e.g., each responsible for a product feature), microservices align well with team structures, allowing teams to work independently on end-to-end features.
  • High Transaction Throughput: Systems with high transaction volumes, such as payment processing, benefit from microservices to isolate critical flows and enable focused performance optimizations.

In summary, Modular monolith enables you to build applications with low coupling, high cohesion, independent modules, and more.

Microservices give you all that, plus independent deployments, resilience, scalability, and the ability to use different technology stacks per service.

We need to view microservices as an end goal rather than an initial approach. Starting with a modular monolithic architecture in the early stages of development can lay a strong foundation, establishing well-defined bounded contexts that make a future transition to microservices smoother.

That’s all for today!

Thank you for taking the time to read this article. I hope you have enjoyed it. If you enjoyed it and would like to stay updated on various technology topics, please consider subscribing for more insightful content.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Anji…
Anji…

Written by Anji…

Technology Enthusiast, Problem Solver, Doer, and a Passionate technology leader. Views expressed here are purely personal.

No responses yet

Write a response