Only 54% of organizations achieve "mostly successful" outcomes with microservices, according to industry research. That means nearly half get the complexity without the benefits. Should you use microservices or a monolith? The answer isn't ideological—it's contextual. This decision guide gives you a framework to evaluate your specific situation, not a one-size-fits-all prescription.
Match architecture to constraints: monolith for <20 engineers, modular monolith for 20-50, evaluate microservices only with proven bottlenecks and team autonomy.
I've watched teams waste years on premature microservices adoption. I've also watched teams suffer with monoliths that should have been decomposed. Both mistakes are expensive. The goal is to match your architecture to your actual constraints.
This guide consolidates lessons from The Microservices Mistake and When Microservices Make Sense into a single decision framework you can reference and share.
The Decision Matrix
Start here. Answer honestly—what you wish were true doesn't matter.
(Not "we might need to scale" — actual measured bottlenecks)
Full Decision Reference
| Your Situation | Recommendation | Confidence |
|---|---|---|
| New project, small team (<10 engineers) | Monolith | High |
| Growing team (10-30), single product | Modular monolith | High |
| Multiple products, autonomous teams | Evaluate service boundaries | Medium |
| 50+ engineers, proven scaling bottlenecks | Targeted service extraction | High |
| 100+ engineers, distinct bounded contexts | Microservices likely appropriate | High |
| Compliance requires isolation (PCI, HIPAA) | Service boundaries at compliance lines | High |
The Three Questions
Before adopting microservices, answer these honestly:
1. Do you have proven scaling bottlenecks?
"We might need to scale" = No. Theoretical future scale doesn't justify current complexity. You need measured, current bottlenecks that can't be solved by better code, caching, or vertical scaling.
Acceptable evidence:
- Specific component hitting resource limits (CPU, memory, connections)
- Deploy times exceeding team tolerance (builds taking 30+ minutes)
- Database locks causing production issues
Not acceptable evidence:
- "We're planning to grow 10x next year"
- "Netflix does it this way"
- "It's best practice"
2. Do you have team autonomy to match?
Microservices without team autonomy = distributed monolith. As Martin Fowler notes, "as team size increases, it's exponentially harder to coordinate people... microservices kind of forces you into an awkward way of working—which is actually what you need with a bigger team anyway." If teams can't deploy independently, if every change requires coordination meetings, if there's a central architecture review board—you don't have microservices. You have a more complex monolith.
Signs you have real autonomy:
- Teams deploy to production without approval from other teams
- Teams choose their own tech stack within guardrails
- Teams own their services end-to-end, including on-call
Signs you don't:
- Cross-team coordination required for most changes
- Centralized release calendar
- Shared databases between services
3. Can you afford the operational overhead?
Microservices multiply operational complexity. You need people and budget for: container orchestration (Kubernetes), service mesh, distributed tracing, centralized logging, secret management, service discovery, and incident response across service boundaries.
The numbers are sobering. Research shows microservices can introduce 2-3x infrastructure costs and significant operational overhead compared to monoliths. If you're already stretched thin on operations, microservices will make it worse.
The Extraction Checklist
If you're extracting a service from an existing monolith, verify these before starting:
- Clear bounded context. Can you draw a line around the service's responsibilities that doesn't require constant cross-boundary communication?
- Stable interface. Is the contract between this component and the rest of the system well-defined and unlikely to change frequently?
- Independent data. Does this component have its own data, or will you need distributed transactions?
- Team ownership. Is there a team that will own this service completely, including operations?
- Deployment independence. Can this service be deployed without deploying anything else?
If you answered "no" to any of these, you're not ready to extract. Work on the monolith's modularity first.
The Modular Monolith Alternative
For most teams, the right answer is neither microservices nor a tangled monolith. It's a modular monolith. In Building Microservices, Sam Newman emphasizes starting with a monolith and evolving toward services only when needed—a position Martin Fowler echoes: "almost all the successful microservice stories have started with a monolith that got too big and was broken up."
- Clear module boundaries with defined interfaces
- Domain-driven design applied within a single codebase
- Modules that could become services later if needed
- Single deployment, single database, simple operations
This gives you the organizational benefits of separation without the operational costs of distribution. When you actually need to extract a service, the boundaries are already clean.
Warning Signs You Chose Wrong
You chose microservices too early if:
- Most "bugs" are integration issues between services
- Developers can't run the full system locally
- Simple changes require coordinated deployments
- You spend more time on infrastructure than features
- Nobody understands how the whole system works
You stayed with a monolith too long if:
- Deploy times exceed 30 minutes
- Teams block each other constantly
- Database locks cause production incidents
- You can't scale specific components independently
- Onboarding takes months because the codebase is too large to understand
Common Mistakes I've Seen
After watching dozens of microservices adoptions, the failure patterns are predictable. Industry research confirms that while 92% of organizations report "some success" with microservices, only 54% achieve "mostly successful" outcomes. Here's what goes wrong most often:
The Database Shortcut
Teams extract a service but keep it reading from the shared database "temporarily." Temporary becomes permanent. Now you have a distributed system with all the complexity but none of the isolation benefits. The service can't be deployed independently because schema changes break it. You've added network hops without adding autonomy.
The fix: No service extraction without data extraction. If you can't give the service its own data store, you're not ready to extract it. Full stop.
The Sync Call Chain
Service A calls Service B, which calls Service C, which calls Service D. Every request now has four network hops, four failure points, and latency that compounds. One slow service degrades everything. You've built a distributed monolith with worse performance characteristics.
The fix: Design for async from the start. If a synchronous chain is more than two services deep, you've probably drawn the boundaries wrong. Consider whether those services should be one service, or whether they should communicate via events rather than HTTP calls.
The Premature Platform Team
Teams create an internal platform team before they have enough services to justify it. That team builds infrastructure nobody uses, creates standards nobody follows, and becomes a bottleneck that slows everyone down. Meanwhile, the two services you actually have don't need a service mesh.
The fix: Wait until you have at least 5-7 services and genuine, repeated pain before creating platform infrastructure. Before that point, let teams solve their own problems. Patterns will emerge naturally, and you'll build the platform you actually need rather than the one you imagined.
The Contract Chaos
Services communicate via APIs, but there's no schema versioning, no compatibility guarantees, no contract testing. Every deployment is a prayer. Teams spend more time debugging integration failures than building features. Breaking changes propagate silently until production explodes.
The fix: Contract testing is non-negotiable. Consumer-driven contracts, schema registries, or at minimum, documented versioning policies. If you can't answer "what happens when I change this field?" you're not ready for microservices.
The Observability Gap
Teams deploy services but can't trace requests across them. When something fails, nobody knows where. Debugging becomes archaeology: correlating timestamps across log systems, guessing at causality. Mean time to resolution goes from minutes to hours.
The fix: Distributed tracing from day one. Not "we'll add it later." Not "when we have time." Before your first service goes to production. OpenTelemetry, Jaeger, Zipkin—pick one. The tool matters less than having any visibility at all.
The Honest Conversation
Before deciding, have this conversation with your team:
- What problem are we actually solving? If you can't name a specific, current problem, you're solving a hypothetical.
- What's our evidence? Opinions don't count. Show metrics, incidents, or bottlenecks.
- What's the cost of being wrong? Microservices are easier to adopt than to reverse. A premature split creates years of complexity.
- Is this resume-driven? Be honest. "Microservices experience" is valuable on a CV. That's a reason to be suspicious of the recommendation, not a reason to adopt.
What Success Actually Looks Like
How do you know if your microservices architecture is working? Not by counting services. Not by how modern your tech stack looks. By these observable outcomes:
Teams deploy independently. A team can ship changes to their service without coordinating with anyone. If most deploys require meetings, you don't have microservices.
Incidents are contained. When a service fails, other services degrade gracefully rather than cascading. Circuit breakers work. Fallbacks exist. Blast radius is limited.
New engineers can understand the boundaries. Someone joining the team can explain which service owns what within their first week. If understanding the architecture takes months, your boundaries are wrong.
You can answer "who owns this?" For any piece of functionality, there's a clear, single team responsible. Shared ownership means no ownership.
If you have these outcomes, your architecture is working—whether you call it microservices or not. If you don't have these outcomes despite having many services, you've adopted the complexity without the benefits. That's the worst of both worlds.
The Bottom Line
The microservices vs. monolith debate is a false dichotomy. The real question is: what architecture matches your current constraints?
Start with the simplest thing that works. Add complexity when you've proven you need it. Keep your options open by maintaining clean boundaries regardless of deployment model.
The best architecture is the one that lets your team ship value to customers. Everything else is implementation detail.
"The best architecture is the one that lets your team ship value to customers. Everything else is implementation detail."
Sources
- Martin Fowler: Monolith First — The case for starting with a monolith
- CNCF Annual Survey 2024 — Kubernetes adoption data and operational requirements
- DHH: The Majestic Monolith — Basecamp's defense of monolithic architecture
Architecture Review
Unsure whether your architecture fits your scale? Get an objective assessment before making expensive decisions.
Request Review