Few architecture debates generate as much strong opinion as monolith versus microservices, and much of that debate happens without being precise about what actually changes between the two. This article focuses on the concrete, structural difference, not the surrounding narrative.
What actually changes
A monolith is an application built and deployed as a single unit — one codebase, one deployment artifact, one running process (or a set of identical replicas of that same process). Different components within it — the parts handling user accounts, orders, notifications, say — communicate through ordinary in-process function calls.
Microservices split an application into multiple independently deployable services, each responsible for a specific piece of functionality, communicating over the network — either through direct calls or through message queues and events — rather than through in-process calls. Martin Fowler’s treatment of microservices is among the most widely cited descriptions of the pattern and its trade-offs in detail.
The single most consequential change in this shift is easy to understate: calls between components that used to be in-process function calls — fast, reliable, and simple to reason about — become network calls between separately deployed services, which are slower, can fail independently, and introduce the entire category of distributed-systems complexity covered elsewhere on this site, including the need for patterns like circuit breakers and distributed tracing that a monolith’s in-process calls simply don’t need.
What microservices genuinely gain
Independent deployment. Each service can be deployed on its own schedule, without needing to coordinate a release with every other part of the system — a real win for CI/CD velocity once an organization has enough separate teams that coordinating a single monolithic deployment across all of them has become the actual bottleneck.
Independent scaling. A service under heavy load can be scaled — more instances, more resources — without having to scale the entire application, which matters when different components genuinely have very different resource and traffic profiles.
Technology flexibility. Different services can use different languages, frameworks, or data stores best suited to their specific problem, rather than every part of the system being constrained to one shared technology stack.
Fault isolation, in principle. A failure contained within one service doesn’t necessarily bring down the entire system — though this benefit only materializes if the system is actually built with the resilience patterns, like circuit breakers, needed to prevent one service’s failure from cascading into others.
What microservices genuinely cost
Distributed systems complexity, unavoidably. Every one of the network-call trade-offs described above is a real, ongoing engineering cost: handling partial failures, reasoning about consistency across services (directly connected to the CAP theorem), and debugging a request that spans multiple services rather than one process.
Operational overhead. More services means more things to deploy, monitor, and keep available — more surface area for the observability and on-call practices discussed elsewhere on this site to actually cover well, and, often, more infrastructure like a service mesh to manage the traffic between them consistently.
Data consistency across service boundaries. A single database transaction that would have been trivial within a monolith often becomes a genuinely hard distributed problem once the data involved is split across multiple services with their own separate data stores.
When each one actually makes sense
A monolith is usually the right starting point for a new system, or for a system with a small team and no pressing scaling or independent-deployment need — the operational simplicity of one deployable unit is a real advantage, not just a limitation to eventually outgrow. Microservices tend to earn their cost specifically once an organization has grown to the point where the coordination cost of many teams deploying one shared monolith has itself become the bottleneck, or where specific components have genuinely divergent scaling needs a monolith can’t address efficiently. Splitting into microservices before either of those pressures is real usually means paying the full distributed-systems cost without yet getting a commensurate benefit.
Key takeaway
The core trade-off between a monolith and microservices comes down to what happens to calls between components: in-process and simple within a monolith, over the network and subject to the full range of distributed-systems failure modes within microservices. Microservices earn that cost specifically when independent deployment, independent scaling, or genuinely divergent technology needs across components become real organizational pressures — not as a default upgrade every system should eventually make.
This article explains general software architecture concepts; the right choice depends heavily on your team size, system, and actual constraints. See our disclaimer.