Split a monolith into 20 microservices and you don't just multiply deployables, you multiply every cross-cutting concern. TLS, retries, timeouts, trace propagation: suddenly each service carries hundreds of lines of networking code that has nothing to do with your business.
That's a shadow codebase, and it's usually the least differentiated code you own. Nobody buys your product because your retry logic is elegant.
The standard fix a shared SDK works until you have more than one language. Then it forks: a Go SDK, a Java SDK, a Node SDK, each implementing "the same" policy slightly differently, each upgrade a rolling migration across every repo.
A service mesh moves all of it into the infrastructure layer:
- mTLS + workload identity — automatic certificate issuance and rotation, zero app code [web:4]
- Uniform retries/timeouts — declared once in YAML, enforced everywhere
- Free observability — metrics, traces, and topology with Prometheus/Jaeger integration out of the box [web:10]
The honest costs: ~60MB + 0.2 vCPU per sidecar [web:15], added latency per hop (independent benchmarks show +166% for sidecar mTLS vs +8% for ambient mode [web:6]), and a new production system to operate.
Full write-up with annotated PeerAuthentication / AuthorizationPolicy / VirtualService YAML, benchmarks, and a "when NOT to use a mesh" decision framework:
👉 Your Microservices Are Hiding a Second Codebase — full article
One-line version: a service mesh doesn't make services smarter; it stops them from pretending to be network engineers.
Are you running a mesh in production, or still maintaining networking SDKs per language? What broke first? 👇
Top comments (0)