UUID v4 vs v7 vs ULID: Which ID Format Should You Use?
Not all unique identifiers are created equal. Understand UUID v4, v7, ULID, and CUID — and how each choice affects your database performance.
Why Unique IDs Matter
In distributed systems, generating IDs without a central coordinator is a fundamental challenge. Auto-incrementing integers from a single database work well in simple setups, but they become bottlenecks when you need to:
- Generate IDs across multiple services or database shards
- Create records client-side before they reach the server
- Merge data from different systems without ID collisions
- Avoid exposing sequential record counts to users
UUID (Universally Unique Identifier) was the original solution, but newer formats like UUID v7 and ULID address significant limitations in the original design.
UUID Structure
A UUID is a 128-bit value typically represented as 32 hexadecimal digits in five hyphenated groups:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
| | | |
| | | └── Variant (N = 8, 9, a, or b)
| | └────── Version (M = 1, 4, 5, 7...)
| └──────── 12 hex chars (time mid)
└────────────────── 8 hex chars (time low)The version nibble (M) tells you how the UUID was generated. The variant nibble (N) identifies the UUID standard (most UUIDs are RFC 4122 variant 2).
UUID Versions Explained
UUID v1 – Timestamp + MAC Address
v1 embeds the current timestamp (100-nanosecond intervals since October 1582) and the machine's MAC address. While sortable by creation time, it exposes the host's MAC address (a privacy concern) and is predictable. Still used in some database drivers (Cassandra, for example).
UUID v4 – Random
v4 is the most widely used UUID version. It fills 122 bits with cryptographically secure random data (only 6 bits are reserved for version and variant). The probability of collision is approximately 1 in 5.3 × 10³⁶ — negligible for virtually every practical application.
Limitation: Random UUIDs are not time-sortable. In a B-tree database index, inserting random UUIDs fragments the index and causes frequent page splits, degrading write performance at scale.
UUID v5 – Namespace + SHA-1
v5 generates a deterministic UUID from a namespace UUID and a name string using SHA-1. The same inputs always produce the same UUID. Useful for generating stable IDs for well-known entities (e.g., a UUID for a URL or a DNS name).
UUID v7 – Unix Timestamp + Random (New Standard)
UUID v7 (standardized in RFC 9562, 2024) encodes a millisecond-precision Unix timestamp in the most significant bits, followed by random bits. This makes v7 UUIDs naturally time-sortable, which dramatically improves database index locality compared to v4.
A UUID v7 looks like:018f9c4a-9b00-7123-8456-426614174000
ULID – Universally Unique Lexicographically Sortable Identifier
ULID was designed specifically to address UUID's sortability problem. It encodes a 48-bit millisecond timestamp followed by 80 bits of randomness, encoded as 26 characters in Crockford's Base32 (uppercase, no ambiguous characters like I, L, O, U):
01HZ9VKPD4R5F6G7H8JK9MABCD
|||||||||| ||||||||||||||||
Timestamp Randomness
(48 bits) (80 bits)ULIDs are lexicographically sortable as strings, making them ideal for databases that use string-based sorting (like DynamoDB) or when you want sort order to reflect creation time.
Side-by-Side Comparison
| Format | Length | Sortable? | Random bits | Standard |
|---|---|---|---|---|
| UUID v4 | 36 chars (with hyphens) | ❌ No | 122 bits | RFC 4122 |
| UUID v7 | 36 chars (with hyphens) | ✅ Yes (ms) | 74 bits | RFC 9562 (2024) |
| ULID | 26 chars | ✅ Yes (ms) | 80 bits | ULID spec (community) |
| UUID v1 | 36 chars (with hyphens) | ✅ Yes (100ns) | Minimal | RFC 4122 |
| UUID v5 | 36 chars (with hyphens) | ❌ Deterministic | 0 (SHA-1) | RFC 4122 |
Database Performance: Sequential vs. Random
The primary reason to prefer UUID v7 or ULID over UUID v4 in most new projects is B-tree index performance. When you insert a random UUID (v4) as a primary key in PostgreSQL, MySQL, or SQLite:
- The new record lands at a random position in the index tree.
- Pages that are 100% full must split, writing half their data to a new page.
- The index becomes fragmented, increasing storage usage and slowing reads.
With UUID v7 or ULID, new records land near the end of the index (since timestamps are monotonically increasing), just like auto-incrementing integers. This means minimal page splits, better write throughput, and more compact indexes.
Benchmarks on PostgreSQL show UUID v7 delivering 2–4x higher insert throughput than UUID v4 at scale, with significantly lower index bloat.
Which Should You Use?
✅ Use UUID v7 for most new projects
It is the modern standard (RFC 9562), time-sortable for database performance, and has excellent library support in Node.js, Python, Go, and Rust.
✅ Use UUID v4 when simplicity matters most
crypto.randomUUID() is built into every modern browser and Node.js 19+. If you're not at a scale where index performance matters, v4 is fine.
✅ Use ULID for string-sortable IDs
DynamoDB, Redis, and log systems where string sort order should reflect time. Also useful when you want IDs that look cleaner than hyphenated UUIDs.
✅ Use UUID v5 for stable, deterministic IDs
When the same input should always produce the same ID — for content addressing, seeding databases, or generating IDs for well-known entities.
⚠️ Avoid UUID v1 in new code
It exposes the host MAC address and has weaker randomness. Use v7 instead for time-ordered IDs.
Generate UUIDs instantly
Use our free browser-based UUID Generator to create RFC 4122 compliant UUIDs in bulk.