UUID vs ULID

When a system needs unique identifiers without a central counter, it usually reaches for a UUID or a ULID — both are 128-bit values that can be generated independently on any machine with a negligible chance of collision. The catch is that the classic random UUID (v4) has no inherent order, which can hurt database performance, and that gap is exactly what newer formats like UUID v7 and ULID were designed to close. The right choice depends on whether you need standards compliance, time-ordering, a compact text form, or the smallest possible impact on your indexes. This guide compares UUID v4 and v7 with ULID, explains how each is structured, and covers the index implications that often decide the matter.

  1. 1. What a UUID is

    A UUID (Universally Unique Identifier) is a 128-bit value, conventionally written as 32 hexadecimal digits in five hyphenated groups like `550e8400-e29b-41d4-a716-446655440000`. It is defined by RFC 9562 (which superseded RFC 4122) and comes in several versions that differ in how the bits are produced. The goal across all of them is that two parties can generate IDs independently and still effectively never collide, removing the need for a shared sequence. A few bits are fixed to encode the version and variant, so not all 128 bits are freely chosen.

  2. 2. UUID v4: random and unordered

    Version 4 is the most widely used UUID: aside from the version and variant bits, all of its bits are random, giving 122 bits of randomness and an essentially zero collision probability in practice. Its strength is simplicity and unpredictability — a v4 value reveals nothing about when or where it was created. The weakness is that consecutive v4 values are scattered with no relationship to each other or to time, which is harmless on its own but becomes a problem when these IDs are used as a database primary key, as the next step explains.

  3. 3. UUID v7: time-ordered

    Version 7, standardised in RFC 9562, was created specifically to combine uniqueness with sortability. It places a 48-bit Unix millisecond timestamp in the most significant bits and fills the remainder with random data, so IDs generated later sort after earlier ones while staying practically collision-free. This time-ordering means new rows are inserted in roughly increasing key order, which is far friendlier to database indexes than the scattered v4. UUID v7 is increasingly the recommended default when you want UUID compatibility but also want the ordering benefits.

  4. 4. ULID: structure and sortability

    A ULID (Universally Unique Lexicographically Sortable Identifier) is also a 128-bit value, but it is split into a 48-bit millisecond timestamp followed by 80 bits of randomness. It is encoded as 26 characters in Crockford Base32 — for example `01ARZ3NDEKTSV4RRFFQ69G5FAV` — which is shorter than a UUID’s 36-character form, case-insensitive, and avoids ambiguous characters like `I`, `L`, `O`, and `U`. Because the timestamp leads and Base32 preserves order, ULIDs sort lexicographically as plain strings in the same order they were created. That sortable text form is ULID’s headline advantage over a classic UUID.

  5. 5. Database index implications

    This is where the choice usually bites. Many databases store rows physically in primary-key order or rely on a B-tree index keyed by it, and inserting random v4 UUIDs scatters writes across the whole index, causing page splits, poor cache locality, and index fragmentation. Time-ordered IDs like UUID v7 and ULID instead append near the end of the index, which keeps inserts sequential, reduces fragmentation, and improves range queries by creation time. As a further note, storing a UUID as a native 16-byte type or binary column is far more efficient than as a 36-character string, so prefer the compact representation whichever format you pick.

  6. 6. Choosing between them

    Reach for UUID v4 when you want maximum standards support and deliberately unpredictable IDs and ordering does not matter, such as opaque tokens or IDs exposed to the public. Choose UUID v7 when you want the broad ecosystem support of UUID but also need insert-friendly, time-ordered keys for a database. Choose ULID when you additionally value the shorter, URL-friendly, lexicographically sortable text form, perhaps in logs or user-facing identifiers — bearing in mind it is a community spec rather than an IETF standard. In all cases, if an identifier embeds a timestamp, remember it leaks the creation time, so do not use one where that information should stay private.

← All developer guides