ULID or UUID v7

ULID7 sectionsUpdated

Same 48-bit millisecond clock, same sorting behaviour. Choose v7 when the value must be a UUID for a column type or a library; choose ULID when the shorter, case-insensitive text form is what people handle.

The two formats solve one problem and differ mostly in presentation. This page lays the differences out so the decision takes a minute, and says what happens if you later change your mind.

ULIDcomputed by the converter itself
in01890a5d-ac96-774b-bcce-b302099a8057out01H455VB4PEX5VSKNK084SN02Q

A v7 and its ULID form carry the same instant

in018f3c00-7c00-7000-8000-00a0c91e6bf6out01HWY00Z00E0080000M34HWTZP

Another v7, same story

Open the converter: ULIDNothing you paste leaves the browser.
On this page (7)

The comparison#

UUID v7ULID
StandardRFC 9562a community specification
Bits128128
Text length3626
Random bits7480
Case sensitivityinsensitive by conventioninsensitive by design
Native database typeyes, uuid in PostgreSQL and othersno, store as UUID or as text
Library supporteverywheregood, but not built in
Monotonic within a millisecondif the generator spends rand_a on a counterif the implementation follows the monotonic variant
Copy-paste and reading aloudhex, easy to confuse 0 and O in some fontsthe alphabet was designed for it

RFC 9562 § 5.7 · UUID Version 7What v7 guarantees that a community spec cannot

The rule#

If the identifier lives in a database column, travels through gRPC, or passes through code that validates a version nibble, use v7: everything already understands it. If the identifier is mostly handled by people, in support tickets, URLs read over the phone or log lines scanned by eye, ULID is ten characters shorter and forgiving about case.

Storing a ULID in a UUID column#

It works, and it is a common pattern: convert on the way in, convert back on the way out. The one honest caveat is that the stored value will not validate as any UUID version, because a ULID has no version bits. Tools that check the nibble will call it non-standard, and they are right: the storage is fine, the label is not.

Changing your mind later#

Both directions are lossless at the bit level, so a migration is a re-encoding rather than a re-issue: the same identifier, printed differently. What is not lossless is meaning: a v7 converted to ULID text loses its version nibble to the eye, and a ULID converted to UUID gains a version it never had. Pick the canonical form once, and convert only at the edges.

RFC 9562 § 6.2 · Monotonicity and CountersMonotonic counters, where the two specifications agree in spirit

Questions people actually ask#

Is ULID better than UUID v7?

Neither is better. They carry the same clock; ULID is shorter and case-insensitive, v7 is standardised and fits native UUID types and libraries.

Can I store a ULID in a PostgreSQL uuid column?

Yes, by converting the 128 bits. The stored value will not report a valid UUID version, because a ULID has no version bits.

Browse the reference