UUID v4 is stateless and unpredictable, which makes it safe for external identifiers but useless for understanding the sequence of events in a distributed system. UUID v7’s millisecond timestamp changes that — you can read when a record was created, sort by creation time across services, and correlate events without a shared sequence counter. This article covers the practical implications for distributed architectures.
What the timestamp gives you
A UUID v7 encodes a 48-bit Unix millisecond timestamp in its leading bits. This means:
- Sort order is creation order. Sorting UUID v7 values lexicographically gives you the same sequence as sorting by creation time. You do not need a separate
created_atcolumn to order records by insertion time. - Timestamp is recoverable. Given any v7 UUID, you can extract when it was created:
parseInt(uuid.replace(/-/g,'').slice(0,12), 16)gives Unix milliseconds. - Cross-service correlation. If Service A creates a record and Service B creates a related record within the same millisecond window, their UUIDs sort together correctly without any coordination.
Event ordering across services
In a monolith, database sequence numbers give you global event order. In a distributed system with multiple services each writing to their own database, there is no global sequence. UUID v7 provides approximate ordering — accurate to the millisecond, with sub-millisecond ordering within a single node via the monotonic counter.
Service A (node 1): 019236a7-b4f2-7000-... (ts: 1727308800000 ms)
Service B (node 2): 019236a7-b4f4-7000-... (ts: 1727308800002 ms)
Service A (node 1): 019236a7-b4f5-7000-... (ts: 1727308800003 ms)
Sorting these three UUIDs lexicographically gives the correct cross-service event sequence. You can reconstruct a timeline of events across services purely from their IDs — no centralised sequence, no distributed transaction.
Distributed tracing and log correlation
Trace IDs and span IDs in distributed tracing systems (OpenTelemetry, Jaeger, Zipkin) are typically 128-bit or 64-bit random values. Replacing them with UUID v7 values adds a timestamp you can use to:
- Determine when a trace started from the trace ID alone
- Sort log lines from multiple services without relying on wall-clock timestamps that may differ between machines
- Filter traces by time range using the ID prefix instead of a separate timestamp index
// OpenTelemetry custom ID generator using UUID v7
import { v7 as uuidv7 } from 'uuid';
const traceId = uuidv7().replace(/-/g, ''); // 32-char hex, 128-bit
const spanId = uuidv7().replace(/-/g, '').slice(0, 16); // 16-char hex, 64-bit
The trace ID now encodes its own start time, making it self-describing.
Multi-node ID generation without coordination
The traditional alternatives to UUID v4 for distributed IDs are:
| Approach | Coordination needed | Sortable | Collision-safe |
|---|---|---|---|
| Auto-increment | Yes — central DB sequence | Yes | Yes |
| Snowflake ID | Yes — node ID assignment | Yes | Yes |
| UUID v4 | No | No | Yes |
| UUID v7 | No | Approximate (ms) | Yes |
| ULID | No | Approximate (ms) | Yes |
UUID v7 sits in the same column as ULID: no coordination, millisecond-precision ordering, collision-safe. The difference is that UUID v7 is an IETF standard with native database type support, while ULID is a community spec with no native type.
Snowflake IDs (used by Twitter/X, Discord, and others) provide stricter ordering guarantees because they embed a node ID and a per-node sequence counter, but they require each node to be assigned a unique ID at startup — a coordination step UUID v7 avoids entirely.
Clock skew and monotonicity
Each node generating UUID v7 values uses its local system clock. If two nodes have different clock values — common in VM environments where clocks drift — their UUIDs will not interleave in strict wall-clock order. Node A at t=1000ms and Node B at t=998ms will produce UUIDs that sort with A before B, even if B’s event “happened” first in real time.
This is acceptable for most use cases. If you need strict global ordering, you need a coordination layer regardless of ID format — no decentralised ID scheme can provide it without synchronised clocks (GPS time, PTP) or a sequencer service.
Within a single node, UUID v7 is strictly monotonic: the RFC 9562 §6.2 Method 1 counter ensures that two UUIDs generated in the same millisecond sort in generation order. A node’s own sequence is always correct.
Practical guidance
Use UUID v7 for:
- Internal database primary keys where creation order is useful
- Event IDs and message IDs in event-driven systems
- Trace IDs and correlation IDs in distributed tracing
- Any ID where “when was this created?” is a useful question
Keep UUID v4 for:
- Public-facing identifiers in URLs and API responses
- Session tokens and capability grants
- Any ID where creation time must not be inferrable
Extracting the timestamp in practice
// JavaScript
function v7Timestamp(uuid) {
return parseInt(uuid.replace(/-/g, '').slice(0, 12), 16);
}
const ms = v7Timestamp('019236a7-b4f2-7000-8d3e-9c1a2b3d4e5f');
console.log(new Date(ms).toISOString()); // 2026-09-25T16:00:00.000Z
# Python
import uuid as _uuid
from datetime import datetime, timezone
def v7_timestamp(u: str) -> datetime:
ms = int(u.replace('-', '')[:12], 16)
return datetime.fromtimestamp(ms / 1000, tz=timezone.utc)
// Go
import "github.com/google/uuid"
u, _ := uuid.Parse("019236a7-b4f2-7000-8d3e-9c1a2b3d4e5f")
ts, _ := u.Time() // returns time.Time for v7
Further reading
- UUID v4 vs UUID v7 — the full comparison of when each version is appropriate
- UUID Security — what v7’s timestamp discloses and when to avoid it
- UUID in Databases — storage types and index performance
Frequently asked questions
Can UUID v7 replace a central sequence counter in distributed systems?
For most use cases, yes. UUID v7's millisecond timestamp gives approximate cross-node ordering without any coordination. Each node generates independently, and UUIDs sort in creation order to millisecond precision. For strict global ordering you still need clock synchronisation or a coordination layer — but UUID v7 handles the 99% case where millisecond-level ordering is sufficient.
Does UUID v7 leak sensitive information?
Yes — the first 48 bits are a Unix millisecond timestamp. Anyone with a v7 UUID can read when the record was created to the millisecond. Two v7 UUIDs also reveal how many records were created between them. Use v4 for externally visible identifiers where creation time or volume is sensitive.
Should I use v4 or v7?
Use v7 for database primary keys (time-sortable, index-friendly) and v4 for anything where creation order could leak information, like tokens or share links.
Can two nodes generate the same UUID v7?
Collision is astronomically unlikely. UUID v7 has 74 bits of randomness (62 in rand_b plus 12 in rand_a when not using a counter). Two nodes generating a UUID in the same millisecond would need those 74 random bits to match — a probability of 1 in 2⁷⁴ (about 1 in 18 quadrillion) per pair of values.
Does UUID v7 require clock synchronisation across nodes?
No coordination is required — each node generates independently. Clock skew between nodes means their UUIDs will not interleave perfectly in time order, but each node's own UUIDs will be monotonically increasing. For globally strict ordering across nodes you need a coordination layer (logical clocks, a sequencer service) regardless of which ID format you use.