It's hard to watch a startup technical presentation today without hearing the word "microservices." The term has become synonymous with modernity, scalability, and good engineering practices. The problem: for most early-stage startups, microservices are the wrong choice — and that choice shows up in delivery velocity weeks, not years, later.
What microservices really are
Microservices is an architectural style in which an application is composed of small, independent services, each running its own process and communicating via APIs or messages. Each service is responsible for a specific business capability and can be developed, deployed, and scaled independently.
That definition sounds attractive. What the definition doesn't include: the operational overhead, the complexity of distributed communication, the need for specialized infrastructure, and the cognitive cost of maintaining multiple systems that need to work together.
Why Netflix, Amazon, and Google do this
The popularized origin of microservices comes from companies like Netflix and Amazon, which migrated from monoliths to distributed services as they grew. The lesson many startups draw: "If it works for them, I should start that way."
The reasoning ignores the context. Netflix migrated from a monolith that was blocking growth with hundreds of engineers and decades of debt. Amazon has dedicated platform teams to abstract the complexity of distributed services.
You have 3–8 engineers trying to validate a product in the market. The context is radically different.
The real cost nobody mentions
When a 5-engineer startup chooses microservices, here's what happens in practice:
- Deployment becomes complex immediately. You need to coordinate deploys across multiple services, version APIs between them, and ensure backward compatibility. What was one deploy becomes an orchestration operation.
- Debugging requires distributed tracing. A bug that previously needed one stack trace now requires correlating logs from 4 different services to understand what happened.
- Integration tests explode in complexity. Ensuring services work together requires sophisticated local test infrastructure or staging environments that cost money.
- Every new feature involves multiple repositories. A change that would be one PR becomes 3 coordinated PRs in different repositories, with dependencies between them.
- New engineer onboarding curve increases. Understanding the system as a whole requires understanding multiple contexts, not one.
When microservices make sense
Microservices solve real problems — the problems of the companies that created them. They make sense when:
- Independent teams need to deploy and scale parts of the system without coordination
- Parts of the system have radically different scale requirements (a search API that needs to scale 100x more than the registration CRUD)
- The company has its own infrastructure platform capable of absorbing the operational complexity
- The product is mature enough that business domain boundaries are clear
None of these criteria apply to a startup with fewer than 50 engineers that is still finding product-market fit.
The modular monolith: the middle ground many ignore
Between "unorganized legacy monolith" and "distributed microservices," there's an option that combines the benefits of both: the modular monolith.
A modular monolith is a single system, but with clear domain boundaries internally. Each module has its own data layer, well-defined interfaces, and can be developed almost independently — but without the distributed communication complexity and operational overhead of multiple services.
When the product grows and the monolith's scale limits are reached, extracting services is much easier when the internal code is already well-organized by domain.
The pattern that works
The pattern I see working consistently for growing startups is: start with a well-built modular monolith, grow to its natural limits (which are larger than most imagine), and extract services surgically where the technical need justifies it.
The decision to extract a service should come from a real problem — not an architectural preference or an aspiration to look more "enterprise." Real problems include: teams that need to deploy independently, components with radically different scale requirements, or parts of the system that need a different technical stack.
Starting with microservices by default is trading future problems for present problems. And present problems, for startups, cost more.