Topic

Monolith vs Modular Architecture for Modern Web Projects

Insights/ Web Architecture & Platforms / Architecture Decisions

08 Nov 2023 - 09 min read

Monolith vs Modular Architecture for Modern Web Projects
Listen to article00:00 / 10:40

What "monolith" and "modular" actually mean

The words get used so loosely that two people having a "monolith vs modular" argument are often arguing about different things. So before the trade-offs, a clean definition.

A monolith is one deployable unit. One codebase, one process, one database, one release. The whole system goes out at once and comes back at once. Inside that unit, the code can be well-organised or a tangled mess, but operationally it ships as one thing.

A modular architecture, in the sense that matters here, is multiple deployable units, each with its own code, its own process, its own data, and its own release cadence. Services talk to each other through APIs or message queues. The whole system is the result of multiple things running and cooperating.

In between those two sits the modular monolith: one deployable unit, but internal modules with strict boundaries, shared infrastructure for one set of things and explicit APIs between modules for another. It ships as a monolith. It is reasoned about as a modular system.

Most "monolith vs modular" debates are really debates about which of these three a specific project should sit in, and at which point it should move from one to another. The pillar context for that decision is in the architecture-choice article; this article is the focused trade-off between the two extremes and the middle ground.

What a monolith actually buys you (and what it costs)

A monolith is the right starting point for almost every web project, and remains the right answer for many of them indefinitely. Five things make it cheap.

Operational simplicity. One process to deploy, one set of logs to read, one runtime to monitor. The on-call story is "is the monolith up". That is not a small thing.

Local reasoning. A change to a function can be traced through the codebase by reading code, with no API contract in the middle, no network failure mode, no version mismatch. Most bugs become tractable in a way distributed systems make hard.

Transactions. A single database means you can update three tables in one transaction without a saga, without eventual consistency, without a compensating action. Many real business problems are simpler when this works.

Deployment cost. One pipeline, one set of credentials, one image, one rollback. Multi-deployable systems multiply this work, and the multiplier is real.

Refactoring freedom. Moving code between modules inside a monolith is a refactor. Moving code between services across a network is a project. Architectures evolve, and the cost of moving things is part of the cost of the architecture.

The price the monolith pays is also predictable. Blast radius: a bad change can take down the whole system at once. Team boundaries: when more than two or three teams ship to the same codebase, coordination cost rises faster than headcount. Scaling: scaling the whole monolith because one subdomain is hot is wasteful. Internal coupling: without discipline, modules that should be separate quietly grow shared dependencies that make later separation painful.

None of these are dealbreakers for most projects. They are the ceiling. The mistake is to treat the ceiling as if it were the floor.

What a modular split actually buys you (and what it costs)

A modular architecture (multiple services, each with its own data and its own release cadence) is the right answer when the project's shape genuinely justifies it. Four things make it valuable.

Independent deployability. A team can ship a change to its service without coordinating with three other teams. At a certain team count, this is the difference between a system that ships weekly and one that ships quarterly.

Bounded blast radius. A bad release in one service degrades that service, not the whole system. For systems where uptime per subdomain matters, this is a real reliability win.

Targeted scaling. The hot service scales independently of the cold ones. For workloads where one subdomain dominates the bill, this is the cheapest way to keep the hosting under control.

Team ownership. Each service has a team, the team owns the service end to end, and the boundaries match the org chart. Conway's Law works for you instead of against you.

The price is also real. Operational tax: every deployable is another thing to monitor, secure, deploy, version, and page someone about. Distributed system failure modes: network partitions, partial failures, retries, idempotency, eventual consistency. None of these go away just because the team is competent. Data fragmentation: each service owns its data, which means cross-service queries, joins and reports become a separate engineering problem. Cognitive load: a developer onboarding into a 12-service system spends weeks on the system itself before being productive on the work.

The mistake here is the inverse of the monolith mistake: assuming that the ceiling of a monolith is closer than it is, and paying the distributed-system tax from day one for benefits that will not materialise for years.

The modular monolith: the middle ground most teams should occupy longer

A modular monolith ships as one deployable but is structured as if it were modular. Internal modules have explicit APIs between them. The database has clear schemas per module, with the discipline that one module does not read another module's tables directly. The codebase is organised so that, in principle, any module could be lifted into a separate service later.

This is the middle ground that most growing teams should sit in for much longer than they do. It buys most of the operational simplicity of a monolith, most of the reasoning clarity of a modular system, and almost all of the optionality of either future direction. The cost is the discipline: without enforcement (linters, package boundaries, code reviews that catch boundary violations), a modular monolith silently degrades into a tangled monolith, and the optionality evaporates.

The signal that a modular monolith is working is that, when the day comes to extract a module into a service, the extraction is a project on the order of weeks rather than a project on the order of years.

"We'll split it later" and the hidden cost of pretending

The phrase "we'll split it later" is the most expensive sentence in many architecture decisions. Said early, it lets the team build a tangled monolith with the comforting belief that the cleanup is a future-you problem. Said later, it turns out that splitting is much more expensive than the team estimated, because three things have happened invisibly.

The shared database has become a tight coupling. Multiple modules read and write the same tables. Any split has to disentangle the data first, which is itself a multi-quarter project, often involving live migrations on real customer data.

Internal calls have become implicit contracts. Functions in one module call functions in another with parameter shapes nobody documented. Replacing those calls with network APIs requires reverse-engineering the contracts before they can be enforced.

Operational expectations have hardened around the single deployable. Deploys, monitoring, on-call rotations, runbooks all assume one process. Splitting means rebuilding all of those for a multi-service world, often while the team that wrote them has moved on.

The discipline that keeps "we'll split it later" honest is to enforce module boundaries from the beginning, even when the system is shipping as one deployable. The discipline that makes "we'll split it later" a slow form of failure is to skip enforcement and trust that future-you will figure it out.

Signs the split is actually justified

Three signals, considered together, mean the modular split is now the right call rather than a fashionable urge.

Team count is past the coordination ceiling. When more than two or three teams routinely block each other on the same codebase, the cost of coordination has crossed the cost of distributing. This is usually somewhere between five and eight engineering teams, depending on the domain.

Blast radius incidents have become recurring. A pattern of incidents where a release in one part of the system takes down something unrelated is a structural signal. It will not be fixed by better testing alone.

One subdomain has fundamentally different scaling needs. A workflow that handles a hundred million events while the rest of the system handles a hundred thousand has earned its own service, regardless of team count. The cost of scaling the whole monolith for one hot subdomain becomes the cheapest argument for the split.

When fewer than two of these are present, the cost of splitting almost always exceeds the cost of staying. When all three are present, the question is no longer whether to split but how to sequence the extraction so the system keeps shipping while it happens.

Final takeaway

Monolith versus modular is not a religious war. It is a question of where the project sits today, where it is going, and how much complexity the team can absorb without losing the ability to ship. Most projects start as monoliths because monoliths are cheap. Many of them stay as monoliths, sensibly, for years. Some of them grow into modular monoliths, then into selectively split services, in that order. The mistake is to pick the architecture that fits a hypothetical future team and a hypothetical future scale, and pay for it in real time.

The wider context, including how this trade-off connects to the rest of a web architecture decision, is collected in the web architecture and platforms insights cluster. And when the question moves from "should we split this" to "we have decided to, and we now need someone to design the boundaries, the APIs and the migration path", that is exactly what my API development and system integration practice is built around.

- Haja Faniry

Related services

Web Application Development

Custom web application development for companies, startups and international organisations.

API Development & System Integration

API development and system integration services to connect platforms, automate workflows and enable seamless data exchange between applications.

Previous Post
When a Headless Architecture Makes Sense
Next Post
How to Choose the Right Web Architecture for a Business Project
Monolith vs Modular Architecture for Modern Web Projects | Haja Faniry