UUID Sorting and Ordering

How UUIDs sort lexicographically, which versions support time-based ordering, and why UUID v1 does NOT sort chronologically despite containing a timestamp.

Concept

Detailed Explanation

UUID sorting behavior varies dramatically between versions. Understanding this is critical for database performance, pagination, and any system that relies on ID ordering.

Lexicographic sort order by version:

Version Chronological when sorted? Why?
v1 No Timestamp bits are scattered
v3, v5 No Hash-based, no temporal data
v4 No Entirely random
v6 Yes Reordered v1 timestamp
v7 Yes Timestamp in most significant bits

Why UUID v7 sorts correctly: UUID v7 places the 48-bit Unix timestamp in the most significant bits (positions 0-47). Since string comparison compares from left to right, and hex digits sort in the same order as their numeric values, UUIDs generated later always sort after UUIDs generated earlier:

018d1a2b-... (generated at time T)
018d1a2c-... (generated at time T+1ms)
018d1a2d-... (generated at time T+2ms)

Why UUID v1 does NOT sort correctly: UUID v1 splits the 60-bit timestamp into three non-contiguous fields in a confusing order:

v1 format: time_low(32) - time_mid(16) - ver(4)+time_hi(12) - var+clock - node

The least significant timestamp bits (time_low) come first in the string, so sorting by string compares the least significant time portion first. This is the opposite of chronological order. UUID v6 was created specifically to fix this by rearranging the timestamp into big-endian order.

Database sort performance:

For UUID v7 columns, you can use the UUID itself for pagination without needing a separate created_at column:

-- Cursor-based pagination with UUID v7
SELECT * FROM events
WHERE id > '018d1a2b-3c4d-7e5f-a6b7-c8d9e0f1a2b3'
ORDER BY id
LIMIT 20;

For UUID v4 columns, sorting produces a random order that has no practical meaning. You need a separate indexed column for meaningful ordering:

-- Must use a timestamp column for ordering with UUID v4
SELECT * FROM events
ORDER BY created_at DESC, id
LIMIT 20;

Java sorting caveat: Java's UUID.compareTo() treats the internal long values as signed, which produces incorrect lexicographic ordering:

// This does NOT match string sort order!
Collections.sort(uuidList);

// Correct approach: compare as strings
uuidList.sort(Comparator.comparing(UUID::toString));

// Or use unsigned comparison (Java 8+):
uuidList.sort((a, b) -> {
    int cmp = Long.compareUnsigned(
        a.getMostSignificantBits(), b.getMostSignificantBits());
    if (cmp != 0) return cmp;
    return Long.compareUnsigned(
        a.getLeastSignificantBits(), b.getLeastSignificantBits());
});

Binary sort order: When UUIDs are stored as BINARY(16), they sort correctly by byte comparison (unsigned), which matches the lexicographic order of the hex string representation. This is another advantage of binary storage for UUID v7.

Use Case

UUID sorting behavior directly impacts cursor-based pagination in REST APIs: with UUID v7 primary keys, the API can use the last-seen UUID as the cursor, eliminating the need for offset-based pagination that degrades with table size.

Try It — UUID Generator

Open full tool