The monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices. is not a legacy architecture you graduate from. It's a legitimate, powerful choice, often the best one.
What makes a monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices. a monolith
A monolith is a single deployable unit. All your code, routes, business logic, data access, compiles and ships as one artifactWhat is artifact?The output files produced by a build step (like a dist/ folder) that are ready to be deployed to a server..
┌─────────────────────────────────────┐
│ Single Process │
│ │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ Routes │ │ Business Logic │ │
│ └──────────┘ └──────────────────┘ │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ Auth │ │ Data Access │ │
│ └──────────┘ └──────────────────┘ │
│ │
│ ┌──────────────┐ │
│ │ Database │ │
│ └──────────────┘ │
└─────────────────────────────────────┘Deployment is trivial
# Build
npm run build
# Deploy
rsync -avz ./dist/ server:/app/
pm2 restart appOne artifactWhat is artifact?The output files produced by a build step (like a dist/ folder) that are ready to be deployed to a server.. One target. No versioning headaches. When something goes wrong, you roll back one thing. With microservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data., a single feature might touch three services that need coordinated deployment.
Debugging is straightforward
In a monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices., you have one stack traceWhat is stack trace?A list of function calls recorded at the moment an error occurs, showing exactly which functions were active and in what order., one set of logs, and one debugger. Set a breakpointWhat is breakpoint?A specific screen width at which a media query applies different CSS rules, or a marker in DevTools where code execution pauses for debugging. and step through every function call.
// In a monolith, this is one function call chain
app.post('/checkout', async (req, res) => {
const user = await getUser(req.userId); // Step into this
const cart = await getCart(user.id); // Then this
const order = await createOrder(user, cart); // Then this
await sendConfirmation(user.email, order); // Then this
res.json(order);
});In microservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data., that same flow crosses four services. Debugging means correlating logs across services and setting up distributed tracingWhat is distributed tracing?Tracking a single request as it travels through multiple services, showing timing and dependencies at each step..
Database transactions actually work
In a monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices., you can wrap multiple operations in a single database transactionWhat is transaction?A group of database operations that either all succeed together or all fail together, preventing partial updates.:
await db.transaction(async (tx) => {
await tx.insert(orders).values(newOrder);
await tx.update(inventory).set({ quantity: sql`quantity - ${item.qty}` });
await tx.insert(payments).values(paymentRecord);
// If ANY of these fail, they ALL roll back
});ACIDWhat is acid?Four guarantees a database makes about transactions: changes are all-or-nothing, data stays valid, concurrent users don't interfere, and saved data survives crashes. transactions give you atomicity for free. Either everything succeeds or nothing does. In microservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data., there's no shared transaction, if payment fails after inventory was deducted, you need compensating transactions (the sagaWhat is saga?A pattern for coordinating multi-service operations where each step has a compensating undo action that runs if a later step fails. pattern) to undo previous steps.
The modular monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices.
"It becomes a big ball of mud" is the biggest criticism of monoliths. That's a code organization problem, not an architecture problem. A modular monolith solves it: organize your code into clear modules with explicit boundaries, but keep them in one deployable unit.
// src/modules/users/index.ts - public API of the users module
export { getUser, createUser, updateUser } from './service';
export type { User, CreateUserInput } from './types';
// Everything else is private to this module
// src/modules/orders/service.ts - orders module uses the users module
import { getUser } from '../users';
async function createOrder(userId: string, items: CartItem[]) {
const user = await getUser(userId); // Direct function call, no network
// ... create order logic
}The key rules: modules only import from each other's public APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses., each moduleWhat is module?A self-contained file of code with its own scope that explicitly exports values for other files to import, preventing name collisions. owns its database tables, and shared types live in a shared module. Shopify runs one of the largest modular monoliths, a single Rails app serving millions of merchants, with module boundaries enforced by tooling.
MonolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices. types compared
| Type | Structure | Deployment | Communication | When it works |
|---|---|---|---|---|
| Traditional monolith | One codebase, no clear boundaries | Single artifact | Direct function calls | Small teams, early-stage products |
| Modular monolith | Clear module boundaries, explicit interfaces | Single artifact | Function calls through public APIs | Medium teams, growing products |
| Distributed monolith (anti-pattern) | Multiple services, tight coupling | Must deploy together | Network calls, but tightly coupled | Never, worst of both worlds |
If your "microservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data." must deploy in a specific order and share a database, you have a distributed monolith, the most common failure mode of premature microservices adoption.
The "monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices. first" approach
Martin Fowler recommends starting with a monolith:
- You don't know your domain boundaries yet. Getting boundaries wrong in microservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data. means a migrationWhat is migration?A versioned script that changes your database structure (add a column, create a table) so every developer and server stays in sync.. In a monolith, it's a refactor.
- You don't have the team size. Microservices need DevOps maturity and observability tooling.
- You don't have the traffic. A single server handles more than people think.
- You'll extract better services later. After a year, you'll know which boundaries are real.
When the monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices. struggles
Monoliths aren't perfect. They struggle when:
- Different parts need different scaling: your image processing burns CPU while your APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. is I/O-bound
- Large teams step on each other: 50 engineers merging into one repo creates bottlenecks
- You need polyglot tech stacks: your ML pipelineWhat is pipeline?A sequence of automated steps (install, lint, test, build, deploy) that code passes through before reaching production. wants Python but your API is Node.js
- Deployment frequency varies: one team ships daily, another ships quarterly, and they block each other
These are problems of scale. If you don't have them, you don't need the solution.
Quick reference
| Concern | Monolith advantage | Microservices advantage |
|---|---|---|
| Deployment | One artifact, simple rollback | Independent deploys per service |
| Debugging | Single stack trace, one debugger | Fault isolation (one service crashes) |
| Data consistency | ACID transactions across all data | Each service owns its data |
| Team coordination | Low overhead for small teams | Team autonomy at scale |
| Performance | No network latency between modules | Independent scaling per service |
| Tech flexibility | One stack (simpler) | Best tool per service |