Microservices vs Monolith: Which Architecture Should You Choose?
Microservices vs monolith explained plainly: why most teams should start with a modular monolith, the real costs of microservices, and the signals that justify splitting.
Most new products should start as a well-structured monolith, which is faster to build, test, deploy and debug with a small team. Microservices make sense later, when several teams keep blocking each other's releases, parts need very different scaling, or failures in one area must not take down the rest, and you have the DevOps maturity to run them.
Photo: Unsplash
On this page
- What a monolith and microservices actually are
- Microservices vs monolith: side-by-side comparison
- Why many teams should start with a monolith
- When microservices are worth it
- The costs teams underestimate
- How to build a monolith that can split later
- Where to start if you need to split
- Conclusion
- Sources
Somewhere in every growing software team, someone says it: “We should move to microservices.” Sometimes they are right. Often, the team has 6 engineers, 1 product and a deployment pipeline that already wobbles, and splitting into 15 services would turn a manageable codebase into a distributed system nobody fully understands.
This guide compares microservices and monoliths on the things that matter in real projects, explains why many teams should start monolithic, and lists the concrete signals that justify splitting.
What a monolith and microservices actually are
A monolith is an application built and deployed as a single unit. The user interface code, business logic and data access live in one codebase, run in one process (or several identical copies of it behind a load balancer) and usually share one database. Many very large products run on monoliths.
Microservices split an application into small, independently deployable services. Microsoft’s Azure Architecture Center describes each service as self-contained, implementing a single business capability within a bounded context, owned by a small team, persisting its own data and communicating with others only through well-defined APIs or messages.
There is a useful middle ground too: the modular monolith. It is one deployable application, but the code is divided into components with clear boundaries and rules about who can call what. Shopify’s engineering team has written publicly about choosing this path for its core Ruby on Rails application, keeping one codebase while defining and enforcing boundaries between components.
Microservices vs monolith: side-by-side comparison
AWS summarizes the trade-off neatly: monoliths need little up-front planning but get harder to maintain as they grow, while microservices need more planning and investment up front and pay back in independent changes and scaling.
| Factor | Monolith | Modular monolith | Microservices |
|---|---|---|---|
| Initial build speed | Fastest | Fast | Slowest |
| Deployment | 1 unit, all at once | 1 unit, all at once | Each service independently |
| Local development | Run 1 app | Run 1 app | Run or mock many services |
| Debugging | Single process, stack traces | Single process | Distributed tracing across services |
| Data consistency | Database transactions | Database transactions | Eventual consistency, sagas, retries |
| Scaling | Scale the whole app | Scale the whole app | Scale each service separately |
| Fault isolation | One bug can affect everything | Better code isolation, same runtime | Failures can be contained if designed for it |
| Team independence | Low as teams grow | Medium | High |
| Tech stack flexibility | One stack | One stack | Different stacks per service |
| Infrastructure and ops | Simple | Simple | Containers, orchestration, gateways, observability |
| Up-front cost | Low | Low to medium | High |
Key takeaway: Microservices do not remove complexity; they move it from the code into the network, the deployment pipeline and the on-call rotation. AWS puts it similarly: microservices expose complexity so teams can manage it, rather than eliminating it.
Why many teams should start with a monolith
Martin Fowler’s widely cited 2015 essay “MonolithFirst” argues that you should not start a new project with microservices, even if you expect to need them later. The reasoning still holds:
- You do not know your boundaries yet. Good service boundaries follow stable business domains. Early in a product’s life, the domain is still shifting. Splitting too early bakes in the wrong boundaries, and moving logic between services is far harder than moving it between modules.
- Speed matters most early. A monolith lets a small team ship features, refactor freely and run the whole system on a laptop. That is exactly what an MVP needs.
- Microservices carry a fixed tax. Microsoft’s guidance lists the challenges: more moving parts, harder testing across service dependencies, network latency, data consistency without ACID transactions across services, versioning and the need for a mature DevOps culture. A 5-person team pays that tax with time it does not have.
- Distributed systems fail in new ways. Timeouts, partial failures, retries that duplicate work and messages that arrive out of order all need handling that a single process gets for free.
There is also a cautionary tale in the other direction. In 2023, an Amazon Prime Video engineering team wrote publicly that it had consolidated a distributed, serverless video-quality monitoring tool into a single process, reporting infrastructure cost reductions of more than 90% and better scaling. It was one tool, not all of Prime Video, but it showed that “more distributed” is not automatically “more scalable.”
When microservices are worth it
Microservices earn their cost when organizational and technical pressure make a single deployable unit the bottleneck. Watch for these signals:
- Teams block each other. Several teams work in the same codebase, and releases queue behind each other’s changes or a shared test suite. Independent deployment is the biggest benefit microservices offer.
- Very different scaling needs. One part (image processing, search, video encoding) needs far more compute than the rest, and scaling the whole app to feed it is wasteful.
- Different reliability requirements. Checkout must stay up even when recommendations fail. Separating critical paths with clear fault isolation becomes worth the complexity.
- Clear, stable domain boundaries. You can name the bounded contexts (billing, catalog, shipping) and they have not changed much in a year.
- Different technology needs. A machine learning component is best written in Python while the core app is in Java or Ruby.
- You have the platform to support it. CI/CD per service, container orchestration, centralized logging, distributed tracing and an on-call process. If these do not exist, build them first.
If you see only 1 of these signals, a modular monolith or extracting a single service is usually enough. If you see 4 or more, a broader move may be justified.
The costs teams underestimate
Before splitting, budget for the work that does not show up in the architecture diagram:
- Infrastructure: containers and an orchestrator such as Kubernetes or a managed container platform. Our guides to Docker vs Kubernetes and Kubernetes explained cover the basics.
- Delivery pipelines: each service needs its own build, test and deploy pipeline. See what is CI/CD.
- Observability: centralized logs, metrics and distributed tracing (for example with OpenTelemetry), so you can follow one user request across many services. Our observability vs monitoring guide explains the difference.
- API contracts and versioning: services must not break their consumers when they change. Decide early between styles such as REST and GraphQL and how you will version them.
- Data ownership: each service should own its data. That often means duplicating some data, using events to keep copies in sync and accepting eventual consistency. Choosing the right store per service is covered in SQL vs NoSQL.
- Cloud spend: more services mean more baseline resources and more network traffic. Keep an eye on it with FinOps practices.
- Platform work: many organizations that run microservices at scale build an internal platform team to give developers paved roads. See platform engineering and developer experience.
How to build a monolith that can split later
Starting with a monolith does not mean starting with a mess. Build it so splitting is possible:
- Organize code by business domain, not by technical layer. A
billingfolder with its own models, logic and tests beats a giantmodelsfolder. - Enforce module boundaries. Modules talk to each other through defined interfaces, not by reaching into each other’s internals or tables. Static analysis or architecture tests can enforce this.
- Keep data ownership clear. Even in one database, decide which module owns which tables, and avoid cross-module joins where you can.
- Use internal events for things that do not need to happen immediately (“order placed” triggers email and analytics), so they are easy to move to a message queue later.
- Invest in automated tests and CI so refactoring stays safe.
- Measure. Track deploy frequency, build time and incidents. Data, not fashion, should tell you when the monolith is the bottleneck.
Where to start if you need to split
If the signals are clearly there, migrate gradually rather than rewriting:
- Pick 1 candidate service with a clear boundary and real pain, such as a module with very different scaling needs or a team that is constantly blocked.
- Use the strangler fig pattern: put a routing layer in front of the monolith, build the new service alongside it, and move traffic over piece by piece. Microsoft’s Azure Architecture Center documents this pattern.
- Move the data last and carefully. Give the new service its own store, sync data during the transition, then cut over.
- Add observability before cutover so you can compare behavior.
- Review after 1 service. If deploys got easier and incidents did not rise, continue. If not, stop and reassess.
Conclusion
The microservices vs monolith debate is less about technology and more about team size, domain maturity and operational readiness. For most new products, a modular monolith is the faster, cheaper and safer starting point. Split when specific, measurable pain appears: teams blocking each other, very different scaling or reliability needs, and stable domain boundaries, backed by a platform that can run distributed systems well. Let the problem pull you toward microservices rather than letting the trend push you.
Sources
- Microsoft Azure Architecture Center: Microservices architecture style — definition, benefits, challenges, best practices and antipatterns
- AWS: The difference between monolithic and microservices architecture — comparison of development, deployment, scaling and investment
- Martin Fowler: MonolithFirst (2015) — the case for starting with a monolith
- Shopify Engineering: Deconstructing the Monolith — a large-scale modular monolith in practice
- Microsoft Azure Architecture Center: Strangler Fig pattern — incremental migration from a legacy system
Frequently asked questions
Is a monolith bad architecture?
No. A monolith is a legitimate architecture and often the best choice for new products and small to mid-sized teams. It is simpler to build, test, deploy and debug. Problems come from poorly structured monoliths with tangled dependencies, not from being a single deployable unit. A modular monolith with clear internal boundaries scales well for many organizations.
When should you switch from a monolith to microservices?
Switch when you see concrete pain: multiple teams blocking each other's releases, parts of the system with very different scaling or reliability needs, and stable domain boundaries you can name. You also need CI/CD, container orchestration and observability in place. Migrate gradually, one service at a time, rather than rewriting everything at once.
What is a modular monolith?
A modular monolith is a single deployable application whose code is divided into well-defined modules with enforced boundaries, usually organized by business domain. Modules communicate through clear interfaces instead of reaching into each other's internals. It keeps the operational simplicity of a monolith while making the code easier to maintain and easier to split into services later.
Are microservices more expensive than a monolith?
Usually, yes, at least at first. AWS notes that microservices need higher up-front investment in infrastructure and skills. You pay for orchestration, more baseline compute, network traffic, observability tooling and engineering time spent on distributed-system problems. The payoff comes for larger organizations through independent deployment and targeted scaling, which can lower costs over time.
Do microservices need Kubernetes?
No, but they do need some way to deploy, scale, restart and route traffic to many services. Kubernetes is a common choice, and managed container platforms or serverless functions are alternatives. Whatever you choose, you will also need per-service CI/CD, centralized logging, metrics and distributed tracing to operate microservices reliably.
How many developers do you need for microservices?
There is no fixed number, but microservices mainly solve coordination problems between multiple teams. Microsoft describes each service as something a single small team can build, test and deploy. If you have only 1 small team, microservices usually add overhead without solving a problem you have, and a modular monolith is the better fit.
Can a monolith scale to millions of users?
Yes. A monolith can scale horizontally by running many identical copies behind a load balancer, with caching, read replicas and a CDN in front. Many large products run on monoliths or modular monoliths. The limits that push teams toward microservices are more often organizational, such as release coordination, than raw traffic.
Was this guide useful
No reviews yet. Share your experience and help other readers.