The short answer
Quick answer: A monolith is one application, built and deployed as a single unit, usually with one database. Microservices split the system into many small services, each owning its own data, deployed independently and talking over the network. Microservices let large organisations ship and scale parts of a system independently, but they add the full difficulty of distributed systems: network failures, data consistency, and far more operational work. Companies move to microservices when a monolith slows many teams down, and some move back when the overhead outweighs the benefit. For most teams, a well-structured monolith is the right starting point.
What each one is
Monolith
- One codebase, one build, one deployable.
- Modules call each other with ordinary function calls.
- One database, so transactions and joins span the whole system.
Microservices
Martin Fowler and James Lewis's article Microservices gave the style its common definition:
- Small services organised around business capabilities (orders, payments, search).
- Each is independently deployable.
- Each owns its data; no other service touches its database.
- They communicate through APIs or asynchronous messages.
- Teams choose their own tools within limits and own their service in production.
Side by side
| Monolith | Microservices | |
|---|---|---|
| Deployment | One unit; everything ships together | Each service ships on its own |
| Calls between parts | In-process, fast, reliable | Over the network, slower, can fail |
| Data | One database, ACID transactions | A database per service, eventual consistency |
| Scaling | Scale the whole app | Scale individual services |
| Technology | One stack | Mixed, per service |
| Team fit | One team or a few | Many autonomous teams |
| Local development | Run one thing | Run or mock many things |
| Debugging | One stack trace | A trace across many services |
| Operational overhead | Low | High |
Why companies move to microservices
- Teams block each other. With hundreds of engineers in one codebase, merges conflict, builds take an hour, and a release needs everyone's sign-off. Independent services let teams ship on their own schedule.
- Different parts need different scaling. If image processing needs fifty machines and the admin panel needs one, scaling them together is wasteful.
- Fault isolation. A memory leak in recommendations should not take down checkout.
- Different technical needs. One part suits Python and machine learning libraries; another needs low-latency Go.
- Clear ownership. A team owns a service end to end, including being on call for it.
The underlying force is organisational. Conway's law observes that systems tend to mirror the communication structure of the organisations that build them. Microservices are as much a way to structure teams as to structure software.
What it costs
Every function call that becomes a network call inherits the problems described in why distributed systems are hard:
- Calls fail and slow down. You need timeouts, retries, circuit breakers and idempotency.
- No shared transactions. An order that touches inventory, payments and shipping can no longer be one database transaction. You need patterns such as sagas (a sequence of local transactions with compensating actions) and must accept eventual consistency.
- No joins across services. Data must be fetched through APIs or duplicated.
- Operational load. Dozens of pipelines, dashboards and on-call rotations. You need container orchestration (see what Kubernetes does), service discovery, and centralised logs, metrics and tracing.
- Harder testing. A realistic test needs many services running, or careful contract tests.
- Versioning. Services deploy independently, so every API change must stay compatible with older callers.
- Performance. Chains of network calls add latency.
Small teams often find they have traded a code organisation problem for an infrastructure problem.
The distributed monolith
The worst outcome is splitting the code into services without achieving independence:
- Services share a database.
- A feature needs changes to five services, deployed in a fixed order.
- One service failing breaks most of the others.
This has all the costs of microservices and none of the benefits. It usually comes from splitting by technical layer, or drawing boundaries before the domain was understood.
Why some companies move back
Several well-known engineering teams have publicly described consolidating services back into fewer, larger ones. The common reasons:
- Cost. Passing data between many small components can be far more expensive than doing the work in one process.
- Overhead out of proportion to team size. A team of ten running forty services spends its time on plumbing.
- Boundaries were wrong. Features kept crossing service lines.
- Performance. In-process calls are faster than network calls.
Moving back is not failure. It reflects that the right architecture depends on the organisation's size and the problem's shape, and both change.
The middle path: a modular monolith
You can get much of the benefit of clear boundaries without the network:
- One deployable, but strictly separated modules.
- Each module has a public interface; others may not reach into its internals.
- Each module owns its tables, even within one database.
- Boundaries are enforced by tooling, not just by convention.
A modular monolith is easier to operate and gives you well-defined seams. If one module later needs independent scaling or its own team, it can be extracted into a service with far less risk. Fowler's Monolith First argues exactly this: start with a monolith, and split it only once you understand where the boundaries belong.
How to decide
Stay with (or start with) a monolith if:
- You have one team, or a few.
- The product and domain are still changing quickly.
- You do not have a platform team or mature automation.
Consider microservices if:
- Many teams are slowed by sharing one codebase and release.
- Parts of the system have very different scaling or reliability needs.
- You have solid CI/CD, monitoring and on-call practices already.
If you split, do it gradually:
- Modularise inside the monolith first.
- Extract one service where the pain is greatest and the boundary is clear.
- Route traffic to it bit by bit, leaving the rest in place (the "strangler" approach).
- Give the new service its own data.
- Prefer asynchronous messaging for communication where you can; see how message queues work. For synchronous APIs, see REST vs GraphQL vs gRPC.
Frequently asked questions
Are microservices better than a monolith?
Not inherently. They solve problems of scale in teams and traffic, and create problems of complexity. Many successful products run on monoliths.
How big should a microservice be?
Big enough to own a complete business capability and be run by one team. Size in lines of code is not the measure.
What is a modular monolith?
A single deployable application with strongly enforced internal module boundaries. It offers clear structure without distributed-system overhead.
Can microservices share a database?
They can, but it couples them tightly: a schema change can break several services. Each service owning its data is a core principle of the style.
Conclusion
Monolith versus microservices is a trade between simplicity and independence. A monolith keeps everything in one place and easy to reason about. Microservices let many teams move separately, at the price of distributed complexity. Start simple, keep modules clean, and split only when a specific, real pain justifies it.
Related articles
- How Message Queues Like Kafka Decouple Systems
- What Kubernetes Does and Why Companies Use It
- Why Distributed Systems Are So Hard
- REST vs GraphQL vs gRPC: Choosing an API Style
