Guide
6 min read

UUID vs ULID: which identifier should you use?

Both are 128-bit unique identifiers. UUID v4 is the ubiquitous standard. ULID trades the familiar hex format for time-ordered sorting and better database index performance. Here is how to choose.

UUID Generator

Generate v1 and v4 UUIDs

Open

ULID Generator

Generate time-sortable ULIDs

Open

What is a UUID?

A UUID (Universally Unique Identifier) is a 128-bit identifier standardized in RFC 4122. It is formatted as 32 hexadecimal digits split into five groups by hyphens: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.

The most widely used variant is v4, which fills 122 of the 128 bits with cryptographically random data. The remaining 6 bits encode the version and variant. There is no timestamp, no machine identifier, and no sequential structure. Every v4 UUID is effectively random.

UUID v4 (random):
550e8400-e29b-41d4-a716-446655440000
f47ac10b-58cc-4372-a567-0e02b2c3d479
1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed

UUID v1 (timestamp + MAC):
6ba7b810-9dad-11d1-80b4-00c04fd430c8

What is a ULID?

A ULID (Universally Unique Lexicographically Sortable Identifier) is also 128 bits, but it splits those bits differently: 48 bits encode the current Unix timestamp in milliseconds, and 80 bits are random. The result is encoded as 26 characters using Crockford Base32.

The key property: sorting ULIDs alphabetically also sorts them by creation time. Two ULIDs generated in the same millisecond are still ordered correctly because the random portion is monotonically incremented within the same millisecond.

01ARZ3NDEKTSV4RRFFQ69G5FAV
01ARZ3NDEKTSV4RRFFQ69G5FAW  ← same millisecond, monotonically incremented
01ARZ3NDEKSV4RRFFQ69G5FAX   ← next millisecond, sorts after

First 10 chars = timestamp, last 16 chars = randomness

Side-by-side comparison

AspectUUID v4ULID
Format32 hex digits + 4 hyphens (36 chars)26 Crockford Base32 characters
Size128 bits128 bits
Sortable by timeNo (v4 is random)Yes (lexicographic = chronological)
Timestamp encodedNo (v4)Yes (48-bit ms precision)
URL-safeYesYes
StandardizedRFC 4122Community spec (github.com/ulid/spec)
Language supportUniversalGood, most major languages
Database index perfPoor with random v4Good (sequential inserts)
Human readable timeNoFirst 10 chars encode timestamp

The database index problem with random UUIDs

Most relational databases store primary key indexes as B-trees. When you insert a row, the database places its key in the correct sorted position in the tree. With random UUID v4 keys, every insert lands at a random position, forcing the database to load a different disk page almost every time.

This causes two problems at scale: high write amplification (many page reads and writes per insert) and index fragmentation (pages fill unevenly, wasting space and slowing reads). PostgreSQL calls this "index bloat." MySQL InnoDB, which clusters data by primary key, is particularly affected.

ULIDs (and UUID v7) insert near the end of the index because each new ID is larger than all previous ones. This keeps writes on the same hot pages and avoids fragmentation, giving meaningfully better throughput on write-heavy tables.

When to use each

Use UUID v4 when

  • Standard compatibility: most libraries, ORMs, and databases understand UUID out of the box.
  • Opaque IDs: when you explicitly do not want creation time recoverable from the ID.
  • Existing systems: no reason to introduce a new format if UUID already works.
  • Languages with built-in UUID support: Node.js crypto.randomUUID(), Python uuid.uuid4(), Java UUID.randomUUID().

Use ULID when

  • High-insert databases: sequential IDs avoid the index fragmentation that random UUIDs cause in B-tree indexes.
  • Event logs and audit trails: IDs that sort by creation time simplify "show me events after X" queries.
  • Distributed systems: retain UUID-level collision resistance while gaining time-ordering.
  • Debugging: you can read the approximate creation time directly from the first 10 characters of the ID.

Frequently asked questions

Why do random UUIDs hurt database performance?

Most databases store primary key indexes as B-trees. When you insert a row, the database places its key in the correct position in the tree. Random UUIDs scatter inserts across the entire tree, forcing the database to load many different disk pages for each write. Sequential or time-ordered IDs insert near the end of the tree, keeping writes on the same few pages. At high insert rates this difference is significant: benchmarks on PostgreSQL and MySQL show 20-30% write throughput improvement with ordered IDs.

Is a ULID truly unique if two are generated in the same millisecond?

Yes. The ULID spec requires monotonic random increments within the same millisecond: the first ULID in a millisecond gets a random suffix, and each subsequent one increments it by 1. This guarantees both uniqueness and sort order even under high concurrency on a single node. Across multiple nodes there is a tiny theoretical collision risk, but 80 bits of randomness make it negligible in practice.

Can I recover the creation time from a ULID?

Yes. The first 10 Crockford Base32 characters encode the Unix timestamp in milliseconds. You can decode them back to a Date object. This is by design: it makes ULIDs useful as a combined ID and timestamp. If exposing creation time is a privacy or security concern, UUID v4 is the better choice.

What is Crockford Base32 and why does ULID use it?

Crockford Base32 is an encoding alphabet that uses 0-9 and A-Z, excluding I, L, O, and U to avoid ambiguity with 0, 1, 0, and V. It produces output that is case-insensitive, URL-safe, and free of characters that look similar in fonts. ULIDs use it because it produces a more compact representation than hex (26 chars vs 36) while remaining safe in URLs, file names, and database columns.

Is UUID v7 a better alternative to ULID?

UUID v7 (defined in RFC 9562, published 2024) encodes a Unix millisecond timestamp in the most significant bits, giving it the same time-ordered property as ULID but in the standard UUID format. If your stack already handles UUIDs natively, v7 is worth considering for new systems. ULID remains a good choice for stacks where the compact 26-character representation is valuable.

What is the difference between UUID v1 and v4?

v1 embeds the current timestamp and the machine MAC address, making IDs time-sortable but potentially leaking machine identity. v4 is fully random (122 bits of entropy) with no timestamp or machine information. v4 is the default choice for most applications. v1 is sometimes used in Cassandra-style databases that rely on timestamp ordering.

Generate UUIDs and ULIDs in your browser

Both tools run entirely client-side. Nothing is sent to a server.

Open UUID generator