UUID in Microservices and Distributed Systems
- Auto-increment IDs require a central counter — microservices can't coordinate safely across services without a shared database.
- UUID v4 can be generated independently on any service node without coordination.
- UUID correlation IDs tie together log entries across multiple services for a single request.
- For event-sourced systems, UUID v7 provides time-ordered event IDs that sort by creation time.
- UUID v5 (deterministic) is useful for cross-service entity references where both sides derive the ID from the same canonical name.
Table of Contents
Auto-increment IDs break in distributed systems. When three services independently write to three databases, who assigns the next integer? The answer requires a central coordinator — and central coordinators are bottlenecks. UUID generation requires no coordination: any service, any node, any time. This guide covers the patterns that make UUIDs effective in microservice architectures.
Why Auto-Increment IDs Break in Microservices
Auto-increment works by asking the database for the next integer in a sequence. In a single-database monolith, this is safe and fast. In a distributed system:
- Multi-database: Service A uses database A, Service B uses database B. Both start incrementing from 1. Order ID 1 exists in both databases. When you merge data or query across services, IDs collide.
- Database sharding: If you shard your database, each shard has its own auto-increment sequence. Row with ID 1 exists on every shard.
- Event streams: Events consumed out of order need a stable ID that the consumer can use as an idempotency key — auto-increment IDs from the producer cannot be used by the consumer because the consumer does not know what integer comes next.
- Client-generated resources: If a client creates a resource (a shopping cart, a draft) before the server processes it, auto-increment requires a round trip to get an ID before the resource exists.
UUID v4 solves all of these: generated in memory, no network round trip, zero coordination, statistically guaranteed unique across all nodes.
UUID Correlation IDs — Trace a Request Across Services
When a user request touches 5 services, each service writes logs. Without a shared ID, you cannot connect those log entries. The pattern:
// API Gateway — assign correlation ID at entry:
const correlationId = req.headers['x-correlation-id'] || crypto.randomUUID();
req.headers['x-correlation-id'] = correlationId;
// Propagate to downstream services via HTTP header:
fetch('http://order-service/orders', {
headers: { 'x-correlation-id': correlationId }
});
// Each service logs with the same ID:
logger.info('order created', { correlationId, orderId: order.id });
// Result: all log entries for one user request share a UUID —
// grep by UUID = complete request trace across all services
This is the basis of distributed tracing (OpenTelemetry, Jaeger, Zipkin). The trace ID is a UUID that threads through every service in the call graph.
Sell Custom Apparel — We Handle Printing & Free ShippingUUID in Event Sourcing and Message Queues
// Event structure — every event gets a UUID:
{
"eventId": "550e8400-e29b-41d4-a716-446655440000", // unique per event
"eventType": "OrderPlaced",
"aggregateId": "a6edc906-2f9f-5fb2-a373-efac406f0ef2", // the order's UUID
"correlationId": "...", // request trace
"timestamp": "2026-04-14T12:00:00Z",
"payload": { "productId": "...", "quantity": 1 }
}
// Consumer idempotency — check if event was already processed:
if (await eventStore.exists(event.eventId)) {
// Already processed — skip, return cached result
return;
}
await processEvent(event);
await eventStore.markProcessed(event.eventId);
The eventId is the idempotency key. Message queues (Kafka, SQS, RabbitMQ) can deliver messages more than once — the UUID lets consumers deduplicate without re-processing.
For time-ordered event logs, UUID v7 is better than v4 — events generated in sequence have UUIDs that sort in chronological order, making event replay and range queries much more efficient.
UUID for Database Sharding
When you shard a database by a primary key, auto-increment integers require a shard routing strategy that distributes IDs across shards — which means a central coordinator or pre-allocated ranges.
UUID sharding is simpler:
// Route by UUID prefix — first 4 chars of UUID = 65,536 possible values:
function getShard(uuid: string, shardCount: number): number {
const prefix = parseInt(uuid.slice(0, 4), 16);
return prefix % shardCount;
}
// Consistent: the same UUID always routes to the same shard.
// No central coordinator needed.
// Shard count can be increased by re-routing a subset of the range.
UUID v4 distributes uniformly across shards because it is random. UUID v7 clusters recent records on the same shard (because recent IDs share a time prefix) — this can cause hot shards. For sharded systems, v4 is often better than v7 for even distribution.
UUID v5 for Cross-Service Entity References
When two services independently need to reference the same entity, UUID v5 provides a way to derive a consistent UUID from a canonical identifier without synchronization:
// Both services agree on a namespace (a UUID v4 you generated once):
const PRODUCT_NAMESPACE = 'a8098c1a-f86e-11da-bd1a-00112444be1e';
// Service A (inventory) derives a UUID for product SKU-123:
const productId = uuidv5('SKU-123', PRODUCT_NAMESPACE);
// "d7c4e5f6-..." — same every time
// Service B (orders) independently derives the same UUID:
const productId = uuidv5('SKU-123', PRODUCT_NAMESPACE);
// "d7c4e5f6-..." — identical, no database lookup needed
// Both services reference the same entity by the same UUID
// without ever talking to each other or a shared registry.
This pattern is especially useful during migrations, when two systems need to share entity references before a proper integration is built.
Generate Correlation IDs and Event UUIDs
The Cheetah UUID Generator produces 1 or 10 RFC-compliant UUID v4 values — ready to paste into your event payloads, service configs, or test fixtures.
Open Free UUID GeneratorFrequently Asked Questions
Why can't microservices use auto-increment IDs?
Auto-increment requires a central database sequence to generate the next integer. In a distributed system with multiple databases or services, there is no single source of truth for "the next integer" — UUIDs are generated locally without coordination.
What is the difference between a correlation ID and a trace ID?
They are often used interchangeably, but technically: a trace ID spans the entire request lifecycle; a span ID identifies one operation within the trace. Both are UUIDs. Correlation ID is a simpler term for the same concept in systems not using formal distributed tracing.
Should I use UUID v4 or v7 in microservices?
Use v4 for IDs that need to be opaque and evenly distributed (session tokens, correlation IDs, sharding keys). Use v7 for event IDs and database primary keys where time-ordering and sequential index insertion matter.
How does UUID prevent duplicate event processing in message queues?
Each event is assigned a UUID as its eventId. The consumer stores processed event IDs. Before processing, the consumer checks if the eventId has been seen — if yes, it skips the event. This makes the consumer idempotent against duplicate deliveries.
Can I use the same UUID as both a primary key and a correlation ID?
No — these are different things. A primary key identifies a resource permanently. A correlation ID identifies a single request/response cycle and is discarded after the request completes. Use separate UUIDs for each purpose.

