The 128 bits, laid out
Both versions pack into the same 128-bit, 32-hex-digit structure — what differs is what fills those bits:
v4: [ 48 random bits ][ 4 version bits = 0100 ][ 12 random bits ][ 2 variant bits ][ 62 random bits ]
v7: [ 48 timestamp bits (ms since epoch) ][ 4 version bits = 0111 ][ 12 random bits ][ 2 variant bits ][ 62 random bits ]
The only structural difference is what occupies the leading 48 bits before the version nibble: pure randomness for v4, a Unix millisecond timestamp for v7. Everything after the version/variant bits is random in both cases.
v4's generation algorithm, step by step
- Generate 122 bits of cryptographically secure randomness.
- Set the version nibble (bits 48–51) to
0100(4). - Set the variant bits (the top 2 bits of the next byte) to
10. - Format the remaining bits as the standard 8-4-4-4-12 hyphenated hex string.
Nothing about the input data matters — no timestamp, no machine identifier — which is exactly why v4 generation can happen entirely offline, with no coordination or external state required beyond a good random source.
v7's generation algorithm, step by step
- Read the current Unix timestamp in milliseconds, pack it into the leading 48 bits.
- Generate the remaining 74 bits (minus version/variant) as cryptographically secure randomness.
- Set the version nibble to
0111(7). - Set the variant bits to
10, same as v4. - Format as the standard hyphenated hex string.
The only added step versus v4 is reading and packing the current time — everything else follows the identical randomness and formatting process.
Why this specific difference matters for sorting
Because the timestamp occupies the leading bits in v7, and hex/string comparison reads left to right, UUIDs generated later naturally sort after ones generated earlier when compared lexicographically as strings — the same property that makes auto-incrementing integers convenient as database keys, without needing centralized coordination to assign the next value. v4's fully random leading bits make lexicographic ordering essentially arbitrary relative to creation time.
Common mistakes
- Assuming v7's timestamp portion is more precise than milliseconds. The spec's 48-bit timestamp field captures millisecond resolution — sub-millisecond ordering relies on the remaining random bits, not additional timestamp precision.
- Manually parsing a UUID's timestamp without checking the version nibble first. Attempting to read v4's random leading bits as if they were a v7 timestamp produces meaningless garbage.
- Assuming a monotonic ordering guarantee within the same millisecond. Multiple v7 UUIDs generated in the same millisecond differ only in their random suffix — some implementations add extra monotonicity logic on top, but this isn't guaranteed by the base spec alone.
FAQ
What's the only structural difference between v4 and v7 UUIDs?
The leading 48 bits before the version nibble — fully random in v4, a Unix millisecond timestamp in v7; everything else follows the same random-bits-plus-formatting process.
Does v7 guarantee strict ordering for UUIDs generated in the same millisecond?
Not by the base specification alone — ties within the same millisecond are broken by the random suffix bits, which don't guarantee any particular order; some implementations add extra logic for stricter monotonicity.
Can I extract the creation timestamp from a v7 UUID?
Yes — the leading 48 bits directly encode it; this is also why v7 isn't a good choice if hiding creation time matters, unlike v4.
Generate and inspect the bit layout of v4 and v7 UUIDs with the UUID Generator — entirely client-side.