Skip to main content
ZEKILO Dev
Generate

UUID v4 vs v7 vs ULID: Which ID Should You Use?

Updated 2026.10.03 · 5 min read

UUID v4 is random, while UUID v7 and ULID begin with a timestamp and sort by creation time. Compare their layout, index locality and privacy trade-offs.

Open UUID Generator

For the primary key of a new table, UUID v7 is a good default: it is standardized in RFC 9562, it sorts by creation time, and new rows land next to each other in the index. Keep UUID v4 for identifiers that must not reveal when they were created, and pick ULID when you want the same time-ordered idea in a shorter, 26-character string. You can generate all three and inspect existing values in the UUID Generator.

The three formats at a glance

Item UUID v4 UUID v7 ULID
Defined in RFC 9562, section 5.4 RFC 9562, section 5.7 ULID specification
Size 128 bits 128 bits 128 bits
What is inside 122 random bits, version, variant 48-bit Unix time in milliseconds, 74 more bits, version, variant 48-bit Unix time in milliseconds, 80 random bits
Text form 36 characters (hex digits and hyphens) 36 characters (hex digits and hyphens) 26 characters (Crockford Base32)
Sorts by creation time No Yes Yes
Shows creation time No Yes, to the millisecond Yes, to the millisecond

In UUID v7 the 74 bits after the timestamp are random by default. RFC 9562 also lets a generator use part of them as a counter or as a sub-millisecond time fraction, which matters for ordering inside one millisecond (see below).

How to read the timestamp

A UUID is written as 32 hexadecimal digits in five groups (8-4-4-4-12). The first digit of the third group is the version, and the first digit of the fourth group carries the variant, which is 8, 9, a or b for the UUIDs described in RFC 9562.

In a v7 value, the first 12 hex digits are the Unix time in milliseconds. Take the instant 2026-01-01T00:00:00.000Z, which is 1767225600000 ms:

Unix time (ms)   1767225600000  =  0x019b76daa800

UUID v7          019b76da-a800-7…          time, then version 7
ULID             01KDVDNA00…               the same time in 10 Base32 characters
UUID v4          5962b53c-5d43-4d66-944c-1a3d4c7b6e7c   random, no time inside

The v4 line is one value produced by crypto.randomUUID(); yours will differ every time. Going the other way, pasting 019b76da-a800-7000-8000-000000000000 into the Analyze tab of the tool reports version 7, the RFC 9562 variant and the time 2026-01-01T00:00:00.000Z.

A ULID packs the same 48-bit timestamp into its first 10 characters and 80 random bits into the remaining 16. Its alphabet is Crockford’s Base32 (0123456789ABCDEFGHJKMNPQRSTVWXYZ), which leaves out the letters I, L, O and U, is case insensitive and contains no special characters. Because the most significant part comes first, plain string comparison sorts ULIDs by time, and RFC 9562 says its formats are likewise intended to be lexicographically sortable in their text form.

Why time order helps a database index

RFC 9562 gives the reason for adding time-ordered versions in its own words: UUID versions that are not time ordered, such as UUIDv4, “have poor database-index locality”. New values created one after another are not close to each other in the index, so inserts are performed at random locations, and the RFC notes that the negative effect on B-tree style structures can be dramatic.

With v7 or ULID, each new key is larger than almost all earlier keys, so inserts go to the same end of the index and recently created rows sit together. Section 6.11 of the RFC states that the real-world difference between this locality and random inserts “can be one order of magnitude or more”. That is the RFC’s own estimate, not a measurement made for this guide; the size of the effect on your system depends on the table size, the storage engine and how much of the index fits in memory, so measure before you migrate an existing table.

Two practical points follow from the same RFC:

  • Store the 128-bit value, not the text. Section 6.13 says UUIDs should be stored as the underlying 128-bit binary value where feasible, because the 36-character text needs 288 bits. Use your database’s native UUID type if it has one.
  • Let the database generate the value if you can. The RFC observes that applications using a single database may get the best monotonicity from database-generated UUIDs. As of October 2026, the PostgreSQL 18 documentation lists a built-in uuidv7() function next to uuidv4() and gen_random_uuid().

Order inside the same millisecond

The timestamp has millisecond precision, so two IDs created in the same millisecond are ordered only by what follows the timestamp.

  • UUID v7: RFC 9562 section 6.2 describes optional techniques that keep such values increasing: a fixed-length dedicated counter (Method 1), a monotonic random value (Method 2), or extra clock precision in place of the leftmost random bits (Method 3). A generator may use any of them or none.
  • ULID: the specification says that within the same millisecond sort order is not guaranteed, unless the generator is monotonic and increments the random part by one for each new value.

Either way, IDs created on different machines depend on those machines’ clocks. Treat the order of time-based IDs as “roughly by creation time”, and keep a sequence or an explicit timestamp column when the exact order of events matters. RFC 9562 also recommends treating UUIDs as opaque values and avoiding parsing them unnecessarily, so store created_at in its own column instead of reading it back out of the key.

When UUID v4 is still the right choice

A v7 UUID or a ULID tells anyone who sees it when the record was created. If the ID appears in a public URL, that can reveal a sign-up time or let someone compare the age of two accounts. RFC 9562 calls this a very small attack surface, and its security section adds that when UUIDs are used with any security operation, UUIDv4 should be utilized.

No UUID is a secret, though. The same section says implementations should not assume that UUIDs are hard to guess and must not use them as security capabilities, meaning identifiers whose mere possession grants access. For session tokens, password-reset links or API keys, use a dedicated random token and check authorization on the server.

Situation Reasonable choice
Primary key of a new table, event or log IDs UUID v7
ID shown publicly where creation time should stay private UUID v4
Short, URL-safe, case-insensitive string that sorts by time ULID
Existing v4 keys that cause no measured problem Keep them; both versions are UUIDs

Generating and checking IDs

  1. Open the UUID Generator and choose UUID v4, UUID v7 or ULID.
  2. Set how many you need, from 1 to 1,000, and switch upper case, hyphens or wrapping in braces or quotes as required.
  3. To check an existing value, paste it into the Analyze tab to see its version, variant and, for v1, v6, v7 and ULID, the embedded time.

The values are created in your browser with the Web Crypto API and are not sent anywhere.

Summary

  • UUID v4 is 122 random bits: no order, no embedded time.
  • UUID v7 and ULID start with a 48-bit millisecond timestamp, so they sort by creation time and keep new index entries together.
  • Time-ordered IDs reveal their creation time; use v4 where that matters, and never treat any UUID as a secret.
  • Store UUIDs as 128-bit values and keep a separate timestamp column for exact ordering.

Tools for this guide

Sources

More guides