Reliability & Ops

Correlation IDs

One request often touches many services. A shared identifier lets you follow it end to end across every log and hop.

What you'll learn

  • Explain what a correlation identifier is and why it matters
  • Generate and propagate one across service boundaries
  • Surface the identifier in logs, errors, and support requests
  • Relate correlation identifiers to distributed tracing

5 min

Following one request through many hops

When a single user action fans out into several internal calls, the logs for that action end up scattered across services and machines. A correlation identifier — a unique value created once at the edge and carried through every subsequent call — ties those scattered lines back together. Filter your logs by that one value and the entire journey of the request appears in order.

Without it, debugging a cross-service problem means guessing which log lines belong together by timestamp, which is slow and error-prone. With it, you copy one identifier into a search box and see everything. The cost is tiny; the diagnostic payoff is large.

Generate once, propagate everywhere

Create the identifier as early as possible — typically when a request first enters your system — using a value with negligible collision risk, such as a UUID. If an inbound request already carries one (for example in a header), reuse it rather than minting a new one, so the trace spans system boundaries.

incoming = headers.get('X-Correlation-ID')
correlation_id = incoming or new_uuid()
log.bind(correlation_id=correlation_id)

From there, pass it on every outbound call and bind it to your logger so it appears automatically. See structured logging for how to attach it consistently.

Make it visible where it helps

A correlation identifier earns its keep when humans can see it. Include it in error responses you return to clients, in support tickets, and in user-facing error pages (often labelled a reference). When a partner reports a problem and quotes that reference, you can locate the exact request in seconds instead of trawling by time and endpoint.

Keep the identifier opaque and non-guessable so it cannot be used to probe other requests, and never encode sensitive data inside it. Its only job is to be a unique, shareable handle.

From correlation to tracing

A correlation identifier is the simplest form of request tracing. Full distributed tracing systems extend the idea with a trace identifier plus per-hop span identifiers, timing, and parent-child relationships, letting you see not just which services were involved but how long each took. Open standards exist for propagating this context through headers.

You do not need full tracing on day one. A single propagated correlation identifier delivers most of the debugging benefit, and you can adopt richer tracing later without changing the core habit of carrying context through every call.

Key takeaways

  • Generate one identifier per request at the edge of your system
  • Reuse an inbound identifier so traces cross system boundaries
  • Bind it to your logger so every line carries it automatically
  • Expose it in errors and support references for fast lookup
  • Treat it as the foundation you can later extend into full tracing

FAQ

What format should a correlation identifier use?

Any collision-resistant, opaque value works; a UUID is the common choice. Avoid sequential numbers, which can leak volume information and are easier to guess.

Should I propagate the identifier to external services?

Yes, where they accept one — typically via a request header. It lets both sides correlate the same request, which is invaluable when investigating a shared incident.

Is a correlation identifier the same as a trace identifier?

They overlap. A trace identifier is the tracing-system equivalent; a correlation identifier is the lightweight version you can adopt without a full tracing stack. Many teams map one to the other.

Integrate with Merion

Ready to build?

Read the API reference, grab the OpenAPI spec, and ship a resilient integration.