ksuid.net

ULID vs UUID — Which Unique ID Format Should You Use?

ULID (Universally Unique Lexicographically Sortable Identifier) and UUID (Universally Unique Identifier) are two of the most widely discussed approaches to generating unique identifiers in modern software systems. UUID v4, defined by RFC 4122, has been the industry default for decades and relies on 122 bits of cryptographic randomness to produce identifiers that are virtually guaranteed to be unique. ULID, introduced as an alternative in 2016, embeds a 48-bit millisecond-precision timestamp in the first portion of the identifier, making the resulting values lexicographically sortable by creation time while still providing 80 bits of randomness for uniqueness.

One of the most significant practical differences between the two formats lies in how they interact with database indexes. Because UUID v4 values are entirely random, inserting them into a B-tree index causes random page splits and write amplification, which degrades performance at scale. ULID values, by contrast, are roughly monotonically increasing over time, so new entries are appended near the end of the index, producing far less fragmentation and significantly better write throughput. This makes ULID an especially attractive option for high-write workloads or event-sourcing architectures where ordering matters.

From an encoding perspective, ULID uses Crockford's Base32 to produce a compact 26-character string that is URL-safe, case-insensitive, and free of ambiguous characters. UUID v4, on the other hand, uses the familiar 8-4-4-4-12 hexadecimal format, resulting in a 36-character string (or 32 characters without hyphens). While UUID enjoys universal recognition and native support in virtually every programming language and database, ULID offers a leaner representation and built-in time information without sacrificing uniqueness guarantees in the vast majority of real-world scenarios.

Side-by-Side Comparison

Propertyuliduuid
Bit Length128128
Output Length2636
EncodingCrockford base32hex (8-4-4-4-12)
SortableYesNo
TimestampedYesNo
MonotonicYesNo
Crypto RandomYesYes
StandardRFC 4122

ulid Pros & Cons

Pros

  • Lexicographically sortable by creation time, enabling efficient range queries and chronological ordering without a separate timestamp column
  • Compact 26-character Crockford Base32 encoding that is URL-safe, case-insensitive, and avoids visually ambiguous characters like O/0 and I/l
  • Supports a monotonic generation mode that guarantees strict ordering even for identifiers created within the same millisecond
  • Encodes to exactly 128 bits, making it drop-in compatible with UUID storage columns in most databases when stored in binary form

Cons

  • Not backed by an official RFC or IETF standard, which can be a concern for compliance-sensitive environments or formal API specifications
  • Smaller library ecosystem compared to UUID, with fewer battle-tested implementations across less common programming languages
  • No native database column type in major relational databases, requiring storage as CHAR(26), BINARY(16), or repurposing a UUID column

uuid Pros & Cons

Pros

  • Defined by the widely adopted RFC 4122 standard, giving it formal standing in API specifications, protocols, and regulatory documentation
  • Universal library support across virtually every programming language, framework, and platform with zero external dependencies
  • Native UUID column types in PostgreSQL, SQL Server, and other major databases provide optimized storage, indexing, and query operators
  • Built into standard libraries of most languages (Java, Python, Go, .NET, Ruby), requiring no third-party packages to generate

Cons

  • UUID v4 values are fully random and not sortable, meaning chronological ordering requires an additional timestamp column or index
  • The 36-character hyphenated hex format is verbose and wastes space compared to Base32 or Base62 alternatives
  • Random v4 values cause B-tree index fragmentation in write-heavy workloads, leading to increased page splits and degraded insert performance

Verdict

Choose UUID v4 when broad ecosystem compatibility, standards compliance, and native database support are your top priorities. Choose ULID when you need time-sortable identifiers, compact encoding, or better database write performance. If you want the best of both worlds, UUID v7 (RFC 9562) combines a time-ordered layout with the standard UUID format, making it a strong middle-ground option for new projects.

Frequently Asked Questions

Can I convert between ULID and UUID formats?

Yes. Both ULID and UUID v4 are 128-bit values, so you can convert between them at the binary level. Many ULID libraries provide a toUUID() method that reformats the 128 bits into the standard 8-4-4-4-12 hex representation, and the reverse conversion is equally straightforward.

Is ULID more collision-resistant than UUID v4?

No. ULID provides 80 bits of randomness per millisecond, while UUID v4 provides 122 bits of randomness overall. In practice, both offer collision probabilities that are astronomically small for any realistic workload, but UUID v4 has a mathematically larger random space.

Should I migrate my existing UUIDs to ULIDs?

In most cases, migrating existing data is unnecessary and risky. If your system works well with UUID v4, keep it. Consider adopting ULID (or UUID v7) for new tables or services where sortability and write performance are measurably important, and let the two formats coexist.

© 2024 Carova Labs. All rights reserved