Microservices architecture: when to use them and when not to
Microservices solve specific problems — and create new ones. Learn the signals that tell you when they're worth it and when a monolith is smarter.
Microservices are not a universal upgrade for software quality. They solve specific problems — and introduce significant new ones. Most organisations that adopt microservices would have been better served by a well-structured monolith. This article gives you a clear framework for deciding when microservices actually make sense.
What are microservices?
A microservices architecture is an approach to building software as a collection of small, independently deployable services — each responsible for one specific business capability, communicating with others over a network via APIs or events.
In practice: an e-commerce platform built with microservices has separate services for user management, product catalogue, orders, payments, and notifications. Each service owns its data, has its own deployment pipeline, and can be maintained by a dedicated team. They never share a database — that shared state is exactly what microservices are designed to eliminate.
This contrasts with a monolithic architecture, where all functionality lives in one codebase, built and deployed as a single unit. Both are valid. The choice depends on your organisational scale and complexity — not on what's currently fashionable in the industry.
Advantages and trade-offs.
The benefits of microservices are real but only materialise above a certain threshold of team size and system complexity. The costs are less visible in theory — but dominant in practice.
| Aspect | Benefit | Cost |
|---|---|---|
| Deployment | Deploy services independently — faster release cycles | Requires orchestration (Kubernetes, service mesh) |
| Scalability | Scale individual services horizontally | Every service needs its own scaling logic |
| Team autonomy | Teams work independently on their own services | Cross-service coordination is expensive |
| Technology choice | Each service can use its own tech stack | Fragmentation — higher onboarding overhead |
| Fault isolation | Failure in one service doesn't bring down the system | Distributed failures are hard to diagnose |
| Testability | Each service is smaller and testable in isolation | Integration testing is far more complex |
| Operational load | Independent updates and rollbacks | Every service needs logging, monitoring, and alerting |
A 2023 ThoughtWorks study found that teams introducing microservices without the matching DevOps maturity spent on average 40% more time on infrastructure management than equivalent teams running a well-structured monolith. The technology itself is not the problem — the operational maturity it demands is consistently underestimated.
Monolith vs. microservices.
The monolith vs. microservices debate is a false binary. A monolith is not a synonym for poorly written software. Microservices are not a synonym for engineering maturity. The question is which approach fits your current organisational reality.
| Factor | Monolith | Microservices |
|---|---|---|
| Team size | 1–15 engineers | 20+ engineers across multiple teams |
| Deployment frequency | 1–4 releases per month | Multiple times per day, per service |
| Domain complexity | Manageable, stable boundaries | Complex, diverging subdomains |
| Scalability needs | Uniform — scaling everything is fine | Heterogeneous — specific components under heavy load |
| DevOps maturity | Limited required | High required (CI/CD, observability, orchestration) |
| Downtime tolerance | Some downtime during deployments acceptable | Zero-downtime deployments required |
Amazon, Netflix and Spotify are routinely cited as arguments for microservices. What's left out: they migrated only after their monolith became too large for hundreds of engineers working in parallel. They were solving a problem you most likely don't have yet. Stack Overflow handles millions of daily users on a monolith. Shopify processes billions in transactions on a single large Rails application.
“Don't start with microservices. The majority of the software applications I've seen benefit from a well-structured monolith at first.”— Martin Fowler, microservices.io
When to make the switch.
There are concrete signals that a monolith is reaching its limits. If you recognise several of these, microservices deserve serious consideration.
- Multiple autonomous teams work on the same codebase and constantly block each other on merges and releases.
- Specific parts of your system have radically different scaling needs — your payment service handles 1% of traffic but consumes 50% of server costs.
- Different parts of your system have diverging availability requirements — your reporting module can be offline, your order intake cannot.
- Deploying a small change requires a full regression test cycle and causes significant downtime.
- Your codebase is approaching 100,000+ lines and new engineers take months to become productive.
Equally important: the wrong reasons to choose microservices. 'Because it's modern' is not a reason. 'Because we want to scale later' is not a reason — you don't yet know how or where scaling pressure will come from. 'Because large companies do it' is not a reason — they had a different problem than you do.
The right sequence: start with a well-structured monolith with clean internal boundaries — modules, packages, bounded contexts. If you later hit the concrete limits that microservices solve, extract services one domain at a time. This is the strangler fig pattern: you migrate incrementally, one service at a time, while the existing system keeps running.
Practical implementation tips.
If you've made a careful decision to move to microservices, a handful of principles separate successful transitions from architecture projects that slow organisations down for years.
- Apply Conway's Law deliberately. Conway's Law says a system's architecture mirrors the communication structure of the organisation that builds it. Design your teams and services together. One service, one team — or the inverse. Services owned by multiple teams become maintenance liabilities.
- Invest in observability before you need it. Without centralised logging, distributed tracing, and per-service dashboards, you're blind when things go wrong. Tools like OpenTelemetry, Grafana, and Jaeger are not optional extras in a microservices environment — they're table stakes.
- Set service boundaries by domain, not by technical layer. Services that are too small (nano-services) create explosive network complexity. Services that are too large are just monoliths with network overhead. Use Domain-Driven Design to find the right boundaries through bounded contexts.
- Start with two or three services, not ten. Every service you add increases operational complexity non-linearly. Validate the approach with a small number of services before expanding the architecture.
- Automate contract testing between services. Validating that two services have compatible interfaces needs to happen automatically in CI, not manually in production. Tools like Pact.io detect API breaking changes early, before they reach users.
A practical starting point is the strangler fig pattern. Rather than rewriting your monolith, you gradually wrap new services around it. Identify the component with the most independent value — often payments or notifications — and extract that first. The rest of the monolith stays intact. You learn the operational challenges of microservices without putting everything at risk simultaneously.
Conclusion.
Microservices are a powerful tool for organisations that have genuinely hit the limits of a monolith: too many engineers on the same codebase, heterogeneous scaling requirements, or business demands for independent deployments. For most companies with 50–500 employees, that inflection point hasn't arrived yet.
The sensible approach: build a monolith with clean internal boundaries. Use modules, bounded contexts, and clear internal interfaces. If you later decide to split it up, you've already thought through the boundaries. If you don't, you have a maintainable system that does its job.