What Is a UUID? The Complete Guide to Format, Versions & Use Cases
Understand UUIDs from the ground up: 128-bit structure, hex format explained, how v1/v3/v4/v5/v7 work internally, collision math, real-world use cases, security pitfalls, and language-specific code examples.
What Is a UUID? The Complete Guide to Format, Versions & Use Cases
Every time you sign up for a service, a unique identifier is created for your account. Every API request carries a trace ID. Every row in a distributed database needs a primary key that won’t collide with keys generated on other machines. The solution behind all of these? UUID — Universally Unique Identifier.
This guide explains what UUIDs are, how they’re structured, what each version does under the hood, and when to use (or avoid) them.
UUID at a Glance
A UUID is a 128-bit (16-byte) identifier designed to be globally unique without requiring a central authority. It’s written as 32 hexadecimal digits in the canonical 8-4-4-4-12 format:
550e8400-e29b-41d4-a716-446655440000
|------| |--| |--| |--| |----------|
8 hex 4 4 4 12 hex
That’s 32 hex characters + 4 hyphens = 36 characters total. The hyphens are purely cosmetic — they don’t carry data.
Key facts:
- 128 bits = 2¹²⁸ ≈ 3.4 × 10³⁸ possible values
- Standardized by RFC 9562 (May 2024, supersedes RFC 4122)
- Also called GUID (Globally Unique Identifier) in Microsoft ecosystems — same format, different name
- Supported natively by PostgreSQL (
uuidtype), MySQL (BINARY(16)orCHAR(36)), and virtually every programming language
Anatomy of a UUID
Every UUID encodes two metadata fields in fixed bit positions, regardless of version:
550e8400-e29b-41d4-a716-446655440000
^ ^
| |
Version-┘ └-Variant
Version Field (Bits 48–51)
The 13th hex digit (first digit of the third group) identifies the UUID version:
| Hex Digit | Version | Method |
|---|---|---|
1 | v1 | Timestamp + MAC address |
3 | v3 | MD5 hash of namespace + name |
4 | v4 | Cryptographically random |
5 | v5 | SHA-1 hash of namespace + name |
6 | v6 | Reordered timestamp (RFC 9562) |
7 | v7 | Unix timestamp + random (RFC 9562) |
8 | v8 | Custom / implementation-specific |
Variant Field (Bits 64–65)
The 17th hex digit (first digit of the fourth group) identifies the variant. For RFC 4122/9562 UUIDs, the first bits are 10, which means this hex digit is always 8, 9, a, or b.
Example Breakdown
550e8400-e29b-41d4-a716-446655440000
↑ ↑
4 → v4 a → RFC 4122 variant
This is a UUID v4 (random), RFC 4122/9562 variant.
UUID Versions Explained
Version 1: Timestamp + MAC Address
UUID v1 was the original design. It encodes:
- 60-bit timestamp — 100-nanosecond intervals since October 15, 1582 (the Gregorian calendar reform)
- 14-bit clock sequence — monotonicity counter to prevent duplicates on clock rollback
- 48-bit node — typically the machine’s MAC address
| Timestamp | Ver | Clk |Var| Node (MAC) |
| 60 bits | 4b | 14b |2b | 48 bits |
Problems:
- Exposes the generation time and hardware identity (privacy risk)
- MAC addresses can be spoofed, undermining uniqueness
- The 1582 epoch is confusing and requires conversion
Verdict: Deprecated by RFC 9562. Use v7 instead for time-based UUIDs.
Version 3: MD5 Name-Based (Deterministic)
UUID v3 hashes a namespace UUID and a name string using MD5. The same inputs always produce the same UUID.
import uuid
# namespace = DNS, name = "example.com"
print(uuid.uuid3(uuid.NAMESPACE_DNS, "example.com"))
# → "9073926b-929f-31c2-abc9-fad77ae3e8eb" (always this value)
Four standard namespaces are defined:
- DNS:
6ba7b810-9dad-11d1-80b4-00c04fd430c8 - URL:
6ba7b811-9dad-11d1-80b4-00c04fd430c8 - OID:
6ba7b812-9dad-11d1-80b4-00c04fd430c8 - X.500:
6ba7b814-9dad-11d1-80b4-00c04fd430c8
Verdict: Functional but prefer v5 — SHA-1 is stronger than MD5.
Version 4: Random — The Most Popular
UUID v4 fills 122 bits with cryptographically secure random data (the remaining 6 bits are reserved for the version and variant fields).
| Random | Ver | Random |Var| Random |
| 48 bits | 4b | 12 bits |2b | 62 bits |
With 2¹²² ≈ 5.3 × 10³⁶ possible values, the probability of collision is astronomically low. To reach a 50% chance of at least one collision, you’d need approximately 2.71 × 10¹⁸ UUIDs — that’s 2.71 quintillion.
// Every modern browser and Node.js supports this
const id = crypto.randomUUID();
console.log(id); // → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
Strengths: simple, private, universally supported, no coordination needed.
Weakness: random distribution causes B-tree index fragmentation when used as database primary keys. For database-heavy use cases, consider v7.
Version 5: SHA-1 Name-Based (Deterministic)
Identical to v3 but uses SHA-1 instead of MD5. Same inputs always produce the same UUID.
import uuid
print(uuid.uuid5(uuid.NAMESPACE_DNS, "example.com"))
# → "cfbff0d1-9375-5685-968c-48ce8b15ae17" (always this value)
Use cases:
- Generating stable IDs from URLs or DNS names
- Content-addressable storage keys
- Reproducible test fixtures
Important: v3 and v5 are NOT meant for security. They are deterministic — anyone who knows the namespace and name can reproduce the UUID.
Version 7: Unix Timestamp + Random (Recommended for New Projects)
UUID v7 is the newest version, introduced in RFC 9562 (May 2024). It encodes:
- 48-bit Unix timestamp in milliseconds — monotonically increasing
- 74 bits of cryptographic randomness
| Unix timestamp (ms) | Ver | rand_a |Var| rand_b |
| 48 bits | 4b | 12 bits |2b | 62 bits |
This means v7 UUIDs are naturally sorted by creation time — newer UUIDs are always lexicographically greater than older ones. This property makes them ideal for database primary keys, where B-tree indexes stay sequential rather than fragmenting randomly.
import { v7 as uuidv7 } from "uuid";
const id1 = uuidv7(); // generated at T₁
const id2 = uuidv7(); // generated at T₂ (T₂ > T₁)
console.log(id1 < id2); // → true (lexicographic comparison)
Why it matters for databases: v7’s sequential property reduces index page splits by up to 90% compared to v4, resulting in faster inserts, smaller indexes, and better cache performance.
UUID vs GUID — What’s the Difference?
There is no functional difference. GUID (Globally Unique Identifier) is Microsoft’s name for UUID, used in Windows, .NET, COM, and SQL Server. The format is identical: 128 bits, 8-4-4-4-12 hex.
The only cosmetic difference: Microsoft tools sometimes display GUIDs in uppercase with curly braces:
UUID: 550e8400-e29b-41d4-a716-446655440000
GUID: {550E8400-E29B-41D4-A716-446655440000}
If someone asks about the “difference between UUID and GUID,” the answer is: branding.
Special UUID Values
RFC 9562 defines two special UUIDs:
| Name | Value | Purpose |
|---|---|---|
| Nil UUID | 00000000-0000-0000-0000-000000000000 | Represents absence of value (like null) |
| Max UUID | ffffffff-ffff-ffff-ffff-ffffffffffff | Boundary marker or sentinel value |
Never use these as actual identifiers — they are not unique by definition.
Collision Probability: The Birthday Problem
The “birthday problem” calculates how many UUIDs you need before a collision becomes likely. For UUID v4 (122 random bits):
| UUIDs Generated | Collision Probability |
|---|---|
| 1 million | ~10⁻²² (virtually impossible) |
| 1 billion | ~10⁻¹⁶ (still negligible) |
| 2.71 × 10¹⁸ | 50% (the “birthday bound”) |
To put it in context: if you generated 1 billion UUIDs per second, it would take 86 years to reach a 50% chance of a single collision. In practice, hardware failure, software bugs, and cosmic rays are all more likely to cause a duplicate than UUID v4 math.
The formula: p(n) ≈ n² / (2 × 2¹²²)
How to Validate a UUID
A valid UUID matches this regex pattern (case-insensitive):
^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
This checks:
- The 8-4-4-4-12 hex format
- Version digit is 1–7 (position 15)
- Variant nibble starts with 8, 9, a, or b (position 20)
function isValidUUID(str) {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str);
}
isValidUUID("550e8400-e29b-41d4-a716-446655440000"); // → true
isValidUUID("not-a-uuid"); // → false
Generating UUIDs in Every Language
JavaScript / TypeScript
// Browser & Node.js — built-in v4
crypto.randomUUID();
// npm uuid package — supports v1, v3, v4, v5, v7
import { v4, v7 } from "uuid";
v4(); // random
v7(); // time-ordered
Python
import uuid
uuid.uuid4() # random
uuid.uuid5(uuid.NAMESPACE_DNS, "example.com") # deterministic
# uuid.uuid7() planned for Python 3.14+
Go
import "github.com/google/uuid"
uuid.New() // v4 random
uuid.Must(uuid.NewV7()) // v7 time-ordered
Java
import java.util.UUID;
UUID.randomUUID(); // v4 random
// UUID v7: use com.fasterxml.uuid or java.util.UUID in JDK 21+
SQL (PostgreSQL)
-- v4 (PostgreSQL 13+)
SELECT gen_random_uuid();
-- v7 (PostgreSQL 18+)
SELECT uuidv7();
Common Use Cases
Database Primary Keys
UUIDs let you generate IDs anywhere — in the application, on the client, at the edge — without a database round trip. This enables offline-first architectures and simplifies distributed systems. Use v7 for best index performance, or v4 if you don’t care about ordering.
API Request Tracing
Assign a UUID to every API request at the entry point (gateway, load balancer). Pass it through all downstream services in a header like X-Request-ID. This makes it trivial to correlate logs across microservices.
Idempotency Keys
APIs use UUIDs as idempotency keys to ensure that retried requests don’t create duplicate resources. The client generates a UUID before the first attempt and sends the same UUID on retries.
Session Identifiers
UUIDs provide sufficient uniqueness to prevent session collisions across large user bases. Unlike auto-increment integers, they can’t be enumerated — an attacker can’t guess valid session IDs by incrementing a number.
Content-Addressable Storage
UUID v5 generates deterministic IDs from content. Given the same input, you always get the same UUID — useful for deduplication, caching, and reproducible builds.
Security Considerations
UUIDs Are NOT Security Tokens
UUIDs are designed for uniqueness, not secrecy. Key issues:
- UUID v1 leaks the generation timestamp and MAC address
- UUID v4 has 122 random bits but a predictable structure (version/variant bits are fixed)
- UUID v3/v5 are deterministic — anyone who knows the namespace and name can reproduce the UUID
For security tokens, API keys, or session secrets, use a dedicated CSPRNG with 128+ bits of pure randomness:
// For security tokens — NOT a UUID, but fully random
const token = Array.from(crypto.getRandomValues(new Uint8Array(32)))
.map(b => b.toString(16).padStart(2, "0"))
.join("");
UUID v7 Exposes Creation Time
The first 48 bits of a UUID v7 encode the creation timestamp in milliseconds. Anyone who receives a v7 UUID can extract when it was created:
const hex = "01906b5e-4a3e-7234-8f56-b8c12d4e5678".replace(/-/g, "").slice(0, 12);
new Date(parseInt(hex, 16));
// → 2024-07-01T12:34:56.000Z
If creation time is sensitive information, use v4 instead.
Don’t Use UUIDs to Prevent Enumeration
While UUIDs are harder to guess than sequential integers, they shouldn’t be your only access control mechanism. Always enforce authorization checks — don’t rely on URL obscurity.
Frequently Asked Questions
Why are there hyphens in UUIDs?
The hyphens in the 8-4-4-4-12 format are purely for human readability. They carry no data and are ignored during parsing. Some systems store UUIDs without hyphens (32 hex characters), which is equally valid.
Can two UUIDs ever be the same?
Theoretically yes, practically no. For UUID v4 with 122 random bits, the probability of generating two identical UUIDs is approximately 1 in 5.3 × 10³⁶ for any given pair. At real-world generation rates, you are more likely to be struck by lightning while winning the lottery than to encounter a UUID collision.
Are UUIDs sequential?
Only some versions. UUID v1, v6, and v7 contain timestamps and sort chronologically. UUID v4 is fully random with no ordering. UUID v3 and v5 are deterministic but not ordered.
How much storage does a UUID use?
- Binary: 16 bytes (128 bits) — the most efficient storage
- String (with hyphens): 36 bytes (ASCII)
- String (without hyphens): 32 bytes (ASCII)
Most databases store UUIDs in binary format internally. PostgreSQL’s native uuid type uses exactly 16 bytes.
Should I use UUID or auto-increment for primary keys?
Auto-increment is simpler for single-database applications (smaller, faster, sequential). UUID is better for distributed systems (generate anywhere, no coordination, merge-safe). If using UUID, prefer v7 for best database performance.
What is RFC 9562?
RFC 9562, published in May 2024, is the latest UUID standard. It supersedes RFC 4122 and formally introduces UUID versions 6, 7, and 8. It deprecates v1 in favor of v6/v7 and defines the nil and max UUID values. If you’re implementing UUID generation or validation, RFC 9562 is the authoritative reference.
Can I use UUIDs across different programming languages?
Yes. The UUID format (128-bit, 8-4-4-4-12 hex) is language-agnostic. A UUID generated in JavaScript will be correctly parsed in Python, Go, Java, or any other language with UUID support. This interoperability is one of UUID’s greatest strengths.
Generate, decode, and validate UUIDs instantly with our UUID Generator — supports v1, v4, v5, and v7 with batch generation, 100% in your browser.