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

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.

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.