A UUID is a 128-bit value. The way those bits are divided into fields — and how different UUID versions use those fields — determines everything from sort behaviour to timestamp extraction to collision probability.
The Standard String Format
xxxxxxxx-xxxx-Vxxx-Nxxx-xxxxxxxxxxxx
^ ^ ^ ^ ^
| | | | +-- 48 bits (12 hex chars): random/node
| | | +---- 2 bits: variant (N = 8, 9, a, or b)
| | | 14 bits: clock_seq or random
| | +------------ 4 bits: version (V = 1–8)
| +-------------- 12 bits: time_hi or random
+--------------------------- 32 bits: time_low or random
- Total: 8 + 4 + 4 + 4 + 12 = 32 hex chars = 128 bits
- The 4 hyphens are formatting only — not part of the UUID value
UUID v4 Bit Layout
Bits 0–31 : random_a (32 bits)
Bits 32–47 : random_b (16 bits)
Bits 48–51 : version = 0100 (4 bits, always '4')
Bits 52–63 : random_c (12 bits)
Bits 64–65 : variant = 10 (2 bits, always '8/9/a/b')
Bits 66–127 : random_d (62 bits)
Total random bits: 32 + 16 + 12 + 62 = 122 bits. This is the source of UUID v4’s collision resistance — 2¹²² possible values.
Annotated example:
550e8400-e29b-4 1d4-a 716-446655440000
^^^^ ^ ^
rand ver=4 var=a (1010 in binary → variant 10xx)
UUID v7 Bit Layout
Bits 0–47 : unix_ts_ms (48 bits, Unix millisecond timestamp)
Bits 48–51 : version = 0111 (4 bits, always '7')
Bits 52–63 : seq_hi (12 bits, monotonic counter or random)
Bits 64–65 : variant = 10 (2 bits, always '8/9/a/b')
Bits 66–127 : rand_b (62 bits, random)
Total random/counter bits: 12 + 62 = 74 bits (plus 48-bit timestamp prefix).
Annotated example:
018fbe3a-4c5d-7 b12-8 abc-0123456789ab
^^^^^^^^ ^^^^ ^ ^
ts (ms) ts ver=7 var=8 (1000 → variant 10xx)
The first 12 hex chars (018fbe3a4c5d) encode the Unix timestamp in milliseconds. At time of writing, current Unix ms timestamps have the hex prefix 018... — that will advance to 019... around 2027.
Extracting the UUID v7 Timestamp
function uuidV7ToMs(uuid) {
return parseInt(uuid.replace(/-/g, '').slice(0, 12), 16);
}
function uuidV7ToDate(uuid) {
return new Date(uuidV7ToMs(uuid));
}
uuidV7ToDate('018fbe3a-4c5d-7b12-8abc-0123456789ab');
// → 2024-05-21T...
import uuid
def uuid7_to_ms(u: str) -> int:
return int(u.replace('-', '')[:12], 16)
def uuid7_to_datetime(u: str):
from datetime import datetime, timezone
return datetime.fromtimestamp(uuid7_to_ms(u) / 1000, tz=timezone.utc)
Variant Field Details
The variant field occupies bits 64–65 (the high 2 bits of byte 8). For all RFC 9562 UUIDs, these bits are 10 — which means the hex digit at position 17 of the string is always 8, 9, a, or b:
8 = 1000 ← variant 10xx ✓
9 = 1001 ← variant 10xx ✓
a = 1010 ← variant 10xx ✓
b = 1011 ← variant 10xx ✓
c = 1100 ← variant 110x (Microsoft) ✗
A UUID validator that finds c, d, e, or f at position 17 is a Microsoft GUID from a legacy application — not an RFC 9562 UUID.
Nil and Max UUIDs
The nil UUID (00000000-0000-0000-0000-000000000000) is all zeros — a sentinel value for “no UUID”. The max UUID (ffffffff-ffff-ffff-ffff-ffffffffffff) is all ones — a sentinel for the maximum possible value. Both are defined in RFC 9562 §5.9 and have no version or variant bits set.
Related Resources
- RFC 9562 §4 — UUID format and field layout
- RFC 9562 §5.7 — UUID v7 bit layout
- UUID Tools — interactive UUID parser and bit visualiser
Frequently asked questions
How many bits does a UUID have?
A UUID is exactly 128 bits (16 bytes). In the standard hyphenated string format, 4 bits are used for the version field (position 13) and 2 bits for the variant (high 2 bits of position 17), leaving 122 bits for version-specific data. UUID v4 uses all 122 bits for randomness; UUID v7 uses 48 bits for a Unix millisecond timestamp and 74 bits for a monotonic counter and randomness. See RFC 9562 §4.
Where is the version field in a UUID string?
The version is the single hex digit at position 13 (0-indexed) of the standard UUID string — the first character of the third hyphen-separated group: xxxxxxxx-xxxx-Vxxx-xxxx-xxxxxxxxxxxx. A UUID v7 always has 7 at that position; UUID v4 always has 4. See RFC 9562 §4.
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.
How many bits does a UUID have?
A UUID is exactly 128 bits (16 bytes). In the standard hyphenated string format (xxxxxxxx-xxxx-Vxxx-Nxxx-xxxxxxxxxxxx), the 32 hex digits encode all 128 bits. 4 bits are used for the version field (position 13) and 2 bits for the variant (the high 2 bits of position 17), leaving 122 bits for version-specific data. See RFC 9562 §4 for the canonical field layout.
Where is the timestamp in a UUID v7?
The timestamp occupies the first 48 bits of a UUID v7 — the entire first group (8 hex chars) plus the first 4 chars of the second group. It is a big-endian unsigned integer counting Unix milliseconds. To extract it: parseInt(uuid.replace(/-/g,'').slice(0,12), 16) gives milliseconds since the Unix epoch. The value at index 12 is the version nibble (7), immediately followed by 12 random bits.