What is a service mesh, and do you have enough services to need one?
A mesh moves retries, tracing, and encryption out of your code into a proxy beside every service. What that buys, what the sidecar costs, and the honest threshold.
On this page
- What we'll cover
- What it actually does
- The sidecar, and what it costs
- Mutual TLS, the usual reason
- Traffic control
- Observability that comes free
- The alternatives
- Do you have enough services
- Adopting one without a bad week
- Automating around services with CodeWords
- What to get right first
- Frequently asked questions
- Related reading
A service mesh handles communication between your services — retries, timeouts, encryption, tracing, traffic routing — in a proxy deployed alongside each one rather than in the services themselves. Your code makes a plain call; the proxy applies the policy.
The appeal is that these concerns are identical everywhere, tedious to implement, and inconsistently done when each service handles them itself. The cost is a proxy per service, a control plane to operate, and a layer between your code and the network that is invisible until it is the problem.
What we'll cover
What it actually does
Retries and timeouts, configured rather than coded, applied consistently to every call.
Circuit breaking, so a failing dependency stops being called rather than being hammered while it tries to recover.
Encryption between services, without each service managing certificates.
Identity per service, so a call can be authenticated by which service made it rather than by a shared secret.
Traffic routing — sending a share of requests to a new version, splitting by header, mirroring traffic.
Telemetry. Metrics and traces for every call, without instrumenting each service.
All of it applies to service-to-service traffic, not to calls from outside, which is the gateway's job and a common point of confusion.
The sidecar, and what it costs
The architecture is a proxy beside each service instance, and the costs are real.
Resource overhead per instance. A proxy uses memory and processor time, multiplied by however many instances you run.
Added latency per hop, small individually and meaningful across a call chain of five services.
Another thing to upgrade, in lockstep with the control plane, across every service.
Another place a request can fail, and failures in the proxy are confusing because the service's own logs show a call that never left.
A steep learning curve. Debugging a mesh requires understanding it, and the team that adopted it for simplicity now has a new specialism.
Proxyless and node-level variants exist, trading the per-instance overhead for different limitations, and they are worth knowing about before assuming the sidecar model is the only shape.
Mutual TLS, the usual reason
For many organisations this is the actual motivation, whatever else is discussed.
Every service call is encrypted and mutually authenticated, with certificates issued and rotated by the mesh.
Doing this by hand is genuinely painful — issuing, distributing, and rotating certificates for every service is work nobody wants.
It gives a service identity, so policy can say which services may call which, enforced rather than documented.
That is frequently a compliance requirement, and a mesh is a defensible way to satisfy it.
If this is the reason, say so. A mesh adopted for encryption and identity is a reasonable decision; one adopted because it appeared on an architecture diagram is not, and the difference shows up in whether anybody maintains it.
Traffic control
Weighted routing sends a share of traffic to a new version, which is the mechanism behind canary releases at the service level.
Header-based routing sends specific requests — a test account, an internal user — to a particular version.
Mirroring sends a copy of live traffic to a new version without its responses affecting anybody, which is a genuinely good way to test under real load.
Fault injection deliberately introduces failures and delays, so you can verify that your system handles them rather than assuming it does.
These are valuable and they are not free, and most of them can be achieved by other means at smaller scale — which is the recurring theme of this decision.
Observability that comes free
Every call is measured without any service being instrumented for it — latency, error rate, and volume per service pair.
The service dependency graph becomes visible, derived from actual traffic rather than from a diagram somebody drew.
Traces are propagated through the proxies, though your services still need to pass the headers through for a trace to be complete.
This is often the most immediately useful thing, particularly in an estate where nobody is certain what calls what.
It is not a substitute for application instrumentation. The mesh sees calls, not what happened inside them, and a slow call tells you nothing about why.
The alternatives
Worth enumerating, because they cover a great deal of what a mesh provides.
Libraries. Retries, timeouts, and circuit breaking in a shared client library. Works well with one or two languages and becomes an upgrade problem across many.
The platform. Managed load balancers and container platforms provide encryption in transit, health checking, and basic routing.
A gateway, for traffic entering from outside, which is a different problem but frequently the one people are actually trying to solve.
Doing less. Fewer services means fewer inter-service calls, and the mesh's value is proportional to how much of that traffic exists.
Instrumentation libraries give you tracing without a mesh, with more work and more control.
Do you have enough services
The honest threshold, which is higher than the discourse implies.
Under ten services, probably not. The consistency problem is manageable with a shared library and the overhead is disproportionate.
One language across all of them weakens the case considerably, since a library solves it without a proxy per instance.
Without a platform team, no — a mesh needs somebody who understands it, and an unmaintained one is a component that breaks things nobody can diagnose.
With a compliance requirement for encryption and identity, the case is strong regardless of count.
Adopt incrementally where you do. A mesh applied to a subset of services first is a reasonable way to find out whether it helps before committing everything.
The question to ask: which specific problem are you solving, and what would it cost to solve it another way?
Adopting one without a bad week
If the decision is yes, the rollout has a shape that avoids most of the pain.
Start in a non-production environment long enough that somebody understands the failure modes before production does.
Enable it on a few services, ideally ones that talk to each other, so the mesh is doing something real rather than proxying calls to nothing.
Turn on observability first, which is the lowest-risk capability and the one that delivers value immediately.
Enable encryption in a permissive mode before enforcing it, so services not yet in the mesh keep working during the transition.
Add traffic policy last. Retries and circuit breaking change behaviour, and changing behaviour across an estate at the same time as introducing a new component is two variables at once.
Watch the resource use as you expand, since the per-instance overhead is a number you should measure rather than estimate.
Have a way to disable it, per service, and know that it works.
Automating around services with CodeWords
Much of the work around a service estate is integration rather than infrastructure — reporting across services, connecting them to business systems, reacting to what they emit. CodeWords connects to more than 3,000 integrations.
- Open CodeWords and start a new automation.
- Describe what should happen in plain language to Cody, the automation builder.
- Describe the exceptions explicitly.
- Connect the systems involved once and reuse the connections.
You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.
What to get right first
Name the specific problem before evaluating a mesh. "Inconsistent retries", "we need encryption between services for compliance", "nobody knows what calls what" are all real problems with different best answers, and only some of them point at a mesh. A mesh adopted without a named problem is a component nobody maintains.
Two habits make the difference. Adopt it on a subset of services first, since that tells you what it costs operationally before you have committed the whole estate. And remember it covers service-to-service traffic only — if the problem is traffic arriving from outside, a gateway is the answer and a mesh will not help.
Frequently asked questions
What is the difference between a service mesh and an API gateway?
A gateway handles traffic entering your system from outside; a mesh handles traffic between your services. They solve different problems and are frequently used together, and confusing them is the most common misunderstanding here.
How many services justify a mesh?
More than ten as a rough guide, and the count matters less than the specifics — several languages strengthens the case, a single language weakens it, and a compliance requirement for encryption and identity makes it strong at any size.
What does the sidecar actually cost?
Memory and processor per instance, latency per hop, another component to upgrade across every service, and another place a request can fail — with failures that are confusing because the service's own logs show a call that never left.
Is mutual TLS the main reason to adopt one?
For many organisations, yes. Issuing, distributing, and rotating certificates across every service by hand is genuinely painful, and a mesh does it with service identity attached, which is often a compliance requirement.
Can I get the benefits without a mesh?
Much of them. Shared libraries handle retries and circuit breaking, platforms handle encryption and health checking, gateways handle external traffic, and instrumentation libraries give tracing. The mesh's advantage is consistency across many languages.
Does a mesh give me full observability?
It gives you every call's latency, error rate, and volume, plus the real dependency graph — which is more than most estates have. It sees calls rather than what happened inside them, so it complements application instrumentation rather than replacing it.
What if nobody owns it?
Do not adopt one. A mesh needs somebody who understands it, and an unmaintained one becomes a layer between your code and the network that breaks things nobody can diagnose.
What order should I enable things in?
Observability first, since it is the lowest-risk capability and delivers value immediately. Then encryption in a permissive mode before enforcing. Traffic policy last, because retries and circuit breaking change behaviour and that is a second variable.
What should I verify before expanding?
That you can disable it per service and that doing so works. Measure the per-instance resource overhead on real services too, rather than estimating it — it is the number that determines what full adoption costs.
Are there alternatives to the sidecar model?
Yes — proxyless and node-level variants trade the per-instance overhead for different limitations. They are worth understanding before assuming a proxy beside every instance is the only available shape.