This is the architecture question that shows up in every senior interview. In simple language — a monolith is our whole app as one deployable unit, and microservices split that same app into many small services that talk over the network. Neither is “better”; they trade one set of problems for another.
Monolith — one deployable
A monolith is a single codebase that builds into a single artifact and deploys as one thing. All the features — auth, billing, notifications — live together, call each other as plain in-process function calls, and usually share one database.
Why it’s great, especially early:
- Fast to build. One repo, one deploy, one place to run and debug. No network between modules.
- Simple transactions. A single database means real ACID transactions across features — no distributed-transaction gymnastics.
- Easy to reason about. Call a function, get a result. No serialization, no partial failures, no service discovery.
Where it hurts as it grows:
- Scaling is all-or-nothing. If only the image-processing part is hot, we still have to scale the entire app.
- One tech stack. The whole thing is stuck on one language and framework.
- Deploys get scary. A tiny change means redeploying everything, and one bad module can take the whole process down.
Microservices — many small services
Microservices slice the app into small, independently deployable services, each owning one business capability and (ideally) its own database. They communicate over the network — REST, gRPC, or async messages.
Why teams reach for it:
- Independent scaling. Scale just the checkout service during a sale, leave the rest alone.
- Independent deploys. Teams ship their own service without coordinating one giant release.
- Tech freedom & isolation. Each service can use the best stack for its job, and one crashing service doesn’t necessarily kill the others.
The price — and it’s steep:
- Distributed-system pain. The network is now inside our app. Calls fail halfway, latency stacks up, and we need retries, timeouts, and circuit breakers everywhere.
- No easy transactions. Data spread across service databases means no simple cross-service transaction — we’re into sagas and eventual consistency.
- Operational overhead. Service discovery, distributed tracing, dozens of pipelines, versioned APIs. We’re running a small fleet, not an app.
🗄️
🗄️
🗄️
”Start with a monolith”
The most experienced answer we can give: start with a monolith. Martin Fowler calls it MonolithFirst. Microservices solve problems of scale and team size — problems we usually don’t have on day one. Splitting too early means paying the full distributed-system tax before we even know where the right service boundaries are, and early on those boundaries shift constantly.
The winning move is to build a well-structured monolith, watch where it actually strains, and carve out microservices along seams that have proven themselves — the part that needs its own scaling, or the module a separate team owns. Netflix and Amazon famously moved to microservices, but only after their monoliths were straining under real, known load.
The modular monolith — best of both
There’s a middle ground that’s quietly become the sensible default: the modular monolith. It’s still one deployable, so we keep simple ops and real transactions — but internally it’s split into strict modules with clear boundaries, each owning its own data and only talking to others through defined interfaces (not by reaching into each other’s tables).
Think of it like — microservices’ clean boundaries without the network in between. We get the discipline that makes a future split easy, and if a module ever truly needs to become its own service, the seam is already there. For most teams this is the sweet spot for a long, long time.
Interview soundbite
A monolith is one deployable — simple, fast to build, real transactions, but scales all-or-nothing. Microservices split it into small independently deployable services that scale and deploy on their own and isolate faults, at the cost of real distributed-system complexity: network failures, no easy cross-service transactions, and heavy ops. Best practice is to start with a monolith and extract services only along boundaries that have proven they need it. A modular monolith — one deploy, strict internal modules — gives us most of the benefits without the distributed-system tax.