The Case Against Microservices for Series A Startups
Microservices are an organizational solution to a coordination problem you don't have yet. Here's when they actually help — and when they're a foot-gun.
A Series A startup with 12 engineers decides to "build microservices for scale." Two years later they have 47 services, 6 of which are owned by people who left, distributed tracing that mostly doesn't work, and feature delivery that's slowed by 40%.
This story is so common it's almost a meme. And yet teams keep doing it. Let's talk about why microservices are wrong for almost every startup before Series B — and what to do instead.
What microservices actually solve
Microservices are an organizational solution. They solve:
- Independent deployment when teams own different services. Team A ships to service A without coordinating with team B.
- Independent scaling. The 1% of traffic that needs 10x compute doesn't force the other 99% to scale up.
- Technology heterogeneity. ML team uses Python, payments uses Go, frontend uses Node — different runtimes okay.
- Failure isolation. Service A crashing doesn't take down service B.
Note what's not on that list: "performance," "scalability" of the system as a whole, "clean code." Microservices don't give you those. Often they take them away.
What microservices cost
Every service boundary adds:
- Network calls instead of function calls. 100x slower minimum, plus failure modes (timeouts, retries, idempotency).
- Distributed tracing to debug anything cross-service. Operational complexity.
- Schema versioning between services. Breaking changes become 3-PR migrations.
- Deployment complexity. N services × M environments × deploy pipelines.
- Operational overhead. Each service needs alerts, dashboards, runbooks, on-call coverage.
- Cognitive load. Engineers must hold a mental model of N services and their interactions.
The cost is roughly linear in number of services. The benefit is roughly logarithmic. Past a certain point, you're losing.
The right size for the team
The real heuristic: a service per team, give or take.
If you have 3 teams, you should probably have 3-5 services. If you have 50 teams, 50-100 services makes sense.
Series A with 12 engineers and 2 teams: 2-3 services. Not 47.
When teams are smaller than services, you have engineers context-switching between services constantly. Each service needs maintenance the team can't afford. Engineers don't really "own" a service — they own an owner-less bundle.
What to do instead: the modular monolith
A modular monolith is a single deployable artifact that's internally structured into clear modules with explicit boundaries. The shape:
/src
├── billing/
│ ├── api.ts (public interface for other modules)
│ ├── service.ts (business logic)
│ └── repository.ts (data access)
├── orders/
│ ├── api.ts
│ ├── service.ts
│ └── repository.ts
└── auth/
├── api.ts
├── service.ts
└── repository.ts
Modules talk to each other only through their api.ts. Anything else is a lint error.
You get most of the benefits of microservices:
- Clear boundaries between domains
- Independent reasoning about each module
- Refactor confidence — change a module's internals without affecting callers
- Easy to extract later — when a module truly needs independent scaling, split it into a service
Without the costs:
- One deployment
- One database (with schemas per module if you want)
- Function calls instead of HTTP
- Standard debugging
- One CI pipeline
This shape carries you to ~50 engineers. At that point, you can extract services where the org structure justifies it.
When microservices are right earlier
A few legitimate cases for splitting before Series B:
1. ML pipeline — Python ML stack is genuinely different from your Node/Go business logic. Run it as a service.
2. Public API gateway — strict latency requirements, very different scaling profile, different security boundary.
3. Background workers — batch processing that needs different deployment cadence than the API.
4. Acquired company integration — codebases you can't merge without 6 months of work. Run them in parallel.
These are usually 1-3 services beyond the main monolith. Not 47.
How to extract a service when the time comes
Don't just rip it out. Use the strangler fig pattern:
- Define the boundary. What's the API of the new service?
- Make the monolith call this API internally. Even though the API is implemented in the monolith, refactor callers to use it.
- Implement the new service. It exposes the same API.
- Switch one caller at a time from the monolith implementation to the new service. Use a feature flag.
- Decommission the monolith implementation once all callers are migrated.
This takes weeks, not days. But each step is reversible. You don't have a "big bang migration" that ships broken on launch day.
The signs you should split
Real signals it's time to extract a service:
- The module has its own deploy cadence (changes daily while others are weekly)
- The module has different scaling requirements (always saturated when others idle)
- The module has different SLA requirements (5x stricter latency)
- The module has a different team that doesn't want to coordinate deploys
Note: "the codebase is getting big" is not a signal. "Some engineers want to use Rust" is not a signal.
The post-mortem you'll write later
If you split prematurely, here's the post-mortem you'll write at Series B:
"We adopted microservices in early 2024. By 2026, we had 47 services. Engineering velocity had dropped 40%. We're now spending Q3 consolidating 20 of those services back into the monolith, because they had no team and no clear ownership. The original goal — independent team velocity — never materialized because we never had multiple teams."
Skip this. Build a modular monolith. Split when there's a real reason.
The takeaway
Microservices solve organizational problems. Pre-Series B, you don't have those problems yet. Build a modular monolith with clear internal boundaries. Extract services only when team structure or specific technical needs demand it. You'll ship 2x faster and operate 10x more easily.
Work with me
I consult with engineering teams on AI adoption, cloud architecture, and engineering effectiveness. If this post surfaced a challenge you're facing, let's talk.
Get in touch →Related posts
Explore more on these topics: