0% completed
What Monoliths Do Well
On This Page
- The Definition
- What a Monolith Gives You
- The Modular Monolith
- When a Monolith Is the Right Answer
- How to Explain It
- TL;DR
1. The Definition
When you build and deploy an application as a single unit, you have a monolith. One codebase, one build, one running program, and usually one database. You can run many identical copies of that program at once, and it is still one monolith.
The word has turned into an insult, and that is worth correcting before you go any further. A monolith is not a failed design. It is a deployment decision: everything ships together.
Some of the largest and most reliable systems on the internet are monoliths. Stack Overflow served its entire global question-and-answer traffic for years from a compact monolithic application on a handful of servers. Shopify runs one of the world's largest e-commerce platforms on a Ruby on Rails monolith, on purpose, at a scale most microservices systems never reach. GitHub ran as a Rails monolith through most of its growth.
The mess that people actually complain about has its own name. A big ball of mud is a codebase where everything touches everything and no boundary holds. That can happen in any architecture. Splitting a big ball of mud across a network gives you the same mess, with network calls added in the middle of it.
2. What a Monolith Gives You
The advantages of a monolith are easy to miss. You do not notice them while you have them, and you notice all of them once they are gone.
- In-process calls. An in-process call is a normal function call inside one running program. It takes nanoseconds. It cannot time out, and it cannot half-succeed. There are no retries, no circuit breakers, and no serialization. A circuit breaker is a guard that stops calling a service that keeps failing, and serialization is turning data into bytes so it can travel over a network. A whole category of failure simply does not exist here.
- One database, real transactions. Creating an order, charging a payment, and decrementing inventory can be one ACID transaction. ACID means the database runs those three steps as one all-or-nothing unit, so either all of them happen or none of them do. Getting the same guarantee across services takes a saga, which is a chain of small transactions where every step carries an undo action. It also takes an outbox table, which stores outgoing messages so none are lost, plus idempotency work so a retried request does not run twice. In a monolith it takes
BEGINandCOMMIT. - One place to debug. A stack trace shows you everything that happened. There is one log stream, one place to attach a profiler, and one version of the code running in production at a time.
- One thing to operate. One pipeline, one deployment, one set of dashboards, one on-call rotation. Studies of engineering time consistently find that debugging and operations cost more in distributed systems. One widely quoted survey put the debugging-time difference at around 35%.
- Cheap infrastructure. There is no traffic between services, because there are no other services. You also do not pay for the containers, sidecars, gateways, and message brokers that each service needs. A sidecar is a helper process that runs beside a service and handles work like routing and encryption. Reported figures put microservices infrastructure at 3 to 6 times a monolith's cost for the same functionality.
The transaction point is the one that surprises people most, so here is the same business action in both worlds.
3. The Modular Monolith
A modular monolith is a single deployment unit whose insides are split into modules with enforced boundaries. Each module has a public interface, owns its own slice of the database schema, and never reaches into another module. A reach-in is when one module's code calls another module's internals or reads its tables directly.
That is the third option, and it is the one most people forget. The choice is not only between one tangled program and twenty services. Enforcement can come from the language, through visibility rules and separate packages, from build tooling that fails on a cross-module import, or from both.
Here is the point of that discipline. You get most of the code organization benefits of microservices, which are clear ownership, clean boundaries, and modules you can test on their own, while keeping one deployment, one database, and in-process calls. Shopify is the best known practitioner. They call their approach deliberate modularity, and they have built tooling that enforces component boundaries inside the Rails codebase.
The modular monolith has one more property that matters. It is the best starting point for microservices you may extract later. Well drawn module boundaries are the service boundaries you would want anyway, and a module that already owns its own tables can be moved out with far less rework.
This matters because boundaries are cheap to redraw inside one codebase and expensive to redraw across networked services. Finding your boundaries inside a monolith first is the lower-risk order of work.
💡 Whenever someone frames the decision as monolith or microservices, name the modular monolith as the third option. Most teams that believe they need services need enforced boundaries instead.
4. When a Monolith Is the Right Answer
- Small team. Below roughly 20 to 50 engineers, coordinating inside one codebase is rarely what slows you down. The extra operational work of many services goes to people who have no spare time for it.
- Early product. Before product-market fit, the domain keeps changing. Boundaries you draw today will be wrong in six months. Wrong boundaries in a monolith are a refactor. Wrong boundaries in microservices are a migration across a network.
- No operational maturity yet. Microservices assume automated deployment, centralized logging, distributed tracing, and on-call discipline. Distributed tracing is tooling that follows one request across many services. Adopting the architecture before those basics exist multiplies outages instead of containing them.
- The load is uniform. If the whole system scales together, running more copies of the monolith behind a load balancer works fine. Independent scaling is only worth it when one part's load is very different from the rest.
Those four checks work as one decision flow, and the order matters.
5. How to Explain It
You will have to defend this choice out loud, because someone always asks why the system was not split into more services. A good answer names what the monolith is giving you and what evidence would make you give it up.
The 30-second answer: "A monolith gives you things that are expensive to rebuild in a distributed system: real ACID transactions, in-process calls that cannot fail the way network calls do, one place to debug, and low operational cost. For a small team or an early product I would default to a modular monolith, which is a single deployment with enforced module boundaries, so the code stays organized and the boundaries are ready if we ever need to extract a service. I would move to microservices when there is evidence: teams blocking each other's releases, or one component with a very different scaling or reliability profile."
Questions that usually follow:
- "How do you keep a monolith from becoming a mess?" Enforced module boundaries. Public interfaces between modules, no shared tables across modules, build tooling that fails on a boundary violation, and a named owner for each module. This is the discipline of microservices without the network.
- "Can a monolith really scale?" Horizontally, yes. Run many identical copies behind a load balancer, and scale the database with read replicas and caching. A read replica is a copy of the database that serves reads. What a monolith cannot do is scale one part on its own, because the whole unit scales together. That is the specific limit to name, rather than a vague "monoliths do not scale."
A common mistake: using monolith and legacy as if they mean the same thing, or treating microservices as the mature endpoint every system should reach. Several well known engineering teams have merged services back into larger ones, and have written publicly about how much simpler and cheaper the result was.
6. TL;DR
| A monolith gives you | ACID transactions, in-process calls, one place to debug, one pipeline, 3 to 6x lower infrastructure cost. |
| Modular monolith | One deployment unit with enforced boundaries inside it. The right first choice for most teams, and Shopify is the reference case. |
| Right answer when | Small team, early product, uniform load, or operational maturity not there yet. |
| Real limitation | Everything scales and ships together. No part moves on its own. |
| Top mistake | Treating monolith as a synonym for legacy mess. |
Flashcards Review
What is a monolith?
Reading Progress
0%
On This Page
- The Definition
- What a Monolith Gives You
- The Modular Monolith
- When a Monolith Is the Right Answer
- How to Explain It
- TL;DR