ID Format Comparison Hub
Compare UUID, ULID, Snowflake and ObjectId on size, sortability, timestamps and use cases — with live samples, entirely on this device.
Live samples
Generate a fresh UUIDv4, ULID, Snowflake and MongoDB ObjectId to compare their real shapes side by side.
f47ac10b-58cc-4372-a567-0e02b2c3d47901ARZ3NDEKTSV4RRFFQ69G5FAV- SnowflakeOpen the full Snowflake tool
175928847299117063 - MongoDB ObjectIdOpen the full MongoDB ObjectId tool
507f1f77bcf86cd799439011
Samples are generated on this device and never stored.
| Format | Size | Text length & encoding | Time-sortable | Embedded timestamp | Random bits | Best fit |
|---|---|---|---|---|---|---|
| UUIDv4 | 128 | 36 · Hex (hyphenated) | Not sortable | None | 122 | Random identifiers where order does not matter. |
| UUIDv1 | 128 | 36 · Hex (hyphenated) | Not sortable | 100 ns (since 1582) | 62 | Legacy time-based IDs from older systems. |
| UUIDv6 | 128 | 36 · Hex (hyphenated) | By byte order | 100 ns (since 1582) | 62 | A v1 replacement that sorts by creation time. |
| UUIDv7 | 128 | 36 · Hex (hyphenated) | By byte order | Millisecond | 74 | Time-ordered database keys in new code. |
| ULID | 128 | 26 · Crockford Base32 | By text order | Millisecond | 80 | Sortable IDs you also expose in URLs and logs. |
| Snowflake | 64 | 20 · Decimal | By numeric value | Millisecond | 0 | High-throughput IDs coordinated per machine. |
| MongoDB ObjectId | 96 | 24 · Hex | By byte order | Second | 40 | MongoDB document keys made client- or server-side. |
| KSUID | 160 | 27 · Base62 | By text order | Second | 128 | Sortable IDs with a large random component. |
| NanoID | 126 | 21 · URL-safe alphabet | Not sortable | None | 126 | Short, URL-friendly random IDs for links. |
UUIDv4
What it is
- Size
- 128
- Text length & encoding
- 36 · Hex (hyphenated)
- Time-sortable
- Not sortable
- Embedded timestamp
- None
- Random bits
- 122
Safe in URLs as-is
When to reach for it
Random identifiers where order does not matter.
How it compares
The default UUID: 122 random bits make collisions effectively impossible, but the value carries no timestamp and cannot be sorted. This is the UUID people mean by “UUID vs ULID” — the same 128 bits as a ULID, yet 36 characters to a ULID’s 26.
Defined in
UUIDv1
What it is
- Size
- 128
- Text length & encoding
- 36 · Hex (hyphenated)
- Time-sortable
- Not sortable
- Embedded timestamp
- 100 ns (since 1582)
- Random bits
- 62
Safe in URLs as-is
When to reach for it
Legacy time-based IDs from older systems.
How it compares
Encodes a 60-bit 100-nanosecond timestamp counted from 1582 plus a node identifier, but the time bits are split across three fields, so v1 values do not sort chronologically. UUIDv6 rearranges exactly these bits to fix that.
Defined in
UUIDv6
What it is
- Size
- 128
- Text length & encoding
- 36 · Hex (hyphenated)
- Time-sortable
- By byte order
- Embedded timestamp
- 100 ns (since 1582)
- Random bits
- 62
Safe in URLs as-is
When to reach for it
A v1 replacement that sorts by creation time.
How it compares
The same fields as v1 with the timestamp reordered most-significant-first, so the raw bytes and the hex text both sort in time order. Reach for it when you already hold v1 data; reach for v7 in new systems.
Defined in
UUIDv7
What it is
- Size
- 128
- Text length & encoding
- 36 · Hex (hyphenated)
- Time-sortable
- By byte order
- Embedded timestamp
- Millisecond
- Random bits
- 74
Safe in URLs as-is
When to reach for it
Time-ordered database keys in new code.
How it compares
Leads with a 48-bit Unix-millisecond timestamp, so it is k-sortable like a ULID while staying a standard 36-character UUID. For most “UUID vs ULID” decisions in new code, v7 is the UUID-native answer.
Defined in
ULID
What it is
- Size
- 128
- Text length & encoding
- 26 · Crockford Base32
- Time-sortable
- By text order
- Embedded timestamp
- Millisecond
- Random bits
- 80
Safe in URLs as-is
When to reach for it
Sortable IDs you also expose in URLs and logs.
How it compares
Packs the same 128 bits as a UUID into 26 Crockford-Base32 characters, with a 48-bit millisecond timestamp up front for lexicographic sorting. It is case-insensitive and omits the look-alike letters I, L, O and U.
Defined in
Snowflake
What it is
- Size
- 64
- Text length & encoding
- 20 · Decimal
- Time-sortable
- By numeric value
- Embedded timestamp
- Millisecond
- Random bits
- 0
Safe in URLs as-is
When to reach for it
High-throughput IDs coordinated per machine.
How it compares
A 64-bit integer of timestamp, machine id and per-millisecond sequence — compact at roughly 18–19 digits, but epoch-dependent, so it only decodes with the platform’s own epoch. Because it exceeds 2^53 it must travel as a string in JSON, not a number.
Defined in
MongoDB ObjectId
What it is
- Size
- 96
- Text length & encoding
- 24 · Hex
- Time-sortable
- By byte order
- Embedded timestamp
- Second
- Random bits
- 40
Safe in URLs as-is
When to reach for it
MongoDB document keys made client- or server-side.
How it compares
Twelve bytes shown as 24 hex characters: a 4-byte second-resolution timestamp, 5 random bytes and a 3-byte counter. Roughly time-ordered, but only to the second, and the timestamp field overflows in 2106.
Defined in
KSUID
What it is
- Size
- 160
- Text length & encoding
- 27 · Base62
- Time-sortable
- By text order
- Embedded timestamp
- Second
- Random bits
- 128
Safe in URLs as-is
When to reach for it
Sortable IDs with a large random component.
How it compares
160 bits — a 4-byte timestamp over a custom 2014 epoch plus 128 random bits — rendered as 27 case-sensitive Base62 characters that sort lexicographically. More entropy than a ULID, at one extra character.
Defined in
NanoID
What it is
- Size
- 126
- Text length & encoding
- 21 · URL-safe alphabet
- Time-sortable
- Not sortable
- Embedded timestamp
- None
- Random bits
- 126
Safe in URLs as-is
When to reach for it
Short, URL-friendly random IDs for links.
How it compares
Twenty-one characters from a URL-safe, case-sensitive alphabet give 126 random bits with no timestamp. The alphabet and length are configurable, so size and collision odds are a deliberate choice rather than a fixed spec.
Defined in
Do it offline:$ python -c "import uuid; print(uuid.uuid4())"
How to use it
- Start with the comparison table. Each row is one format; the columns line up size, text length and encoding, whether it is time-sortable, the embedded timestamp, and a one-line best-fit — so a glance answers “which of these sorts?” or “which is shortest?”.
- Open a format's panel for the reasoning behind its row: why UUIDv6 exists, why a Snowflake needs an epoch, what a ULID gives up for its 26 characters. Each panel links straight to the format's specification.
- Generate a live sample. For the four formats with a generator here — UUID, ULID, Snowflake and ObjectId — press Generate, or ⌘/Ctrl+Enter, for a fresh value built on this device, then copy it with one click.
- Follow “Open the full tool” where a format has a dedicated page. UUID, ULID, Snowflake and ObjectId each have their own generator with the bulk output, decoding and format options this hub leaves out.
Put UUID, ULID, Snowflake and MongoDB ObjectId next to each other and the differences that matter surface fast: how many bits each spends, how long its text runs, whether it sorts by time, and what timestamp it hides inside. The table reads without JavaScript, and the panel under each row generates a live sample you can copy. The samples are built in your browser and never leave it.
How it works
Every format here is a fixed budget of bits rendered as text, and the two numbers do not move together. A UUID and a ULID both hold 128 bits, yet a UUID is 36 hexadecimal characters with hyphens while a ULID is 26 Crockford-Base32 characters — the denser alphabet spends ten fewer characters on the same amount of information. A Snowflake is only 64 bits and prints as a bare decimal integer, usually 18 or 19 digits; an ObjectId is 96 bits shown as 24 hex characters; a KSUID packs 160 bits into 27. So “how big is it” has two answers, the storage width and the on-screen width, and choosing a format weighs both.
“Sortable” is not one property but four. A UUIDv4 or a NanoID has no order at all: sort a column of them and you get noise. ULID and KSUID are lexicographically sortable — their text sorts chronologically as plain strings, because a timestamp leads the value and the alphabet keeps byte order. UUIDv6, UUIDv7 and ObjectId are binary-sortable: the raw bytes run in time order and the hex text follows along. A Snowflake is integer-sortable — it orders correctly only when compared as a number, since a shorter decimal string sorts before a longer one. The formats that lead with a millisecond clock, ULID and UUIDv7, are what people mean by “k-sortable”.
When a format embeds a creation time, the resolution differs. ULID, UUIDv7 and Snowflake carry a millisecond timestamp; MongoDB's ObjectId and a KSUID keep only whole seconds, so two values minted in the same second cannot be ordered any finer. UUIDv1 and UUIDv6 are the odd ones out: they store a 60-bit count of 100-nanosecond intervals since 1582, a Gregorian tick inherited from the original spec. UUIDv4 and NanoID hold no time at all. Reading a timestamp back is just slicing the leading field and converting it — no database lookup — which is how an ObjectId reveals its second and a ULID its millisecond straight from the string.
Collision resistance comes from the random bits, and the budgets vary widely. A UUIDv4 spends 122 of its 128 bits on randomness, with six reserved for the version and variant markers; a ULID keeps 80 random bits beside its 48-bit clock; UUIDv7 has 74. An ObjectId is different again — five random bytes plus a three-byte counter that increments per process, so uniqueness inside a second leans on the counter, not on chance. A Snowflake reserves no random bits at all: it stays unique by coordinating a machine id and a per-millisecond sequence instead. More randomness lengthens the odds against a duplicate, but it also means nothing sorts — which is the trade the whole table is really about.
Examples
01ARZ3NDEKTSV4RRFFQ69G5FAV2016-07-30T23:54:10.259ZThe first ten Crockford-Base32 characters are a 48-bit millisecond timestamp; the remaining sixteen are 80 bits of randomness. Slicing and decoding the head recovers the creation time with no lookup — the same instant this ULID has carried since the spec's own example.
507f1f77bcf86cd7994390112012-10-17T21:13:27.000ZAn ObjectId leads with four bytes — eight hex characters — of Unix time in whole seconds. Two ObjectIds made in the same second share that prefix and cannot be ordered more finely; the trailing counter, not the clock, breaks the tie.
UUIDv4 vs ULIDSame 128 bits — 36 characters versus 26The headline of the whole “UUID vs ULID” question: an identical entropy budget, but Crockford-Base32 packs it into ten fewer characters, which is why a ULID reads more kindly in a URL or a log line. Neither is “bigger” in storage; they differ only in text.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
A UUIDv4 has no order to sort by
The most common misread on this page is expecting a UUID to sort. A v4 is 122 random bits and nothing else — line up a thousand of them by text or by bytes and the order is meaningless. If you need creation order out of a UUID, that is exactly what v6 and v7 add; a plain v4 will never give it to you.
UUIDv1 stores the time but scrambles it
UUIDv1 does embed a timestamp, which tempts people into sorting it — but the spec splits the clock across low, mid and high fields, so neither the text nor the bytes run in time order. UUIDv6 keeps the identical information and simply reorders those fields most-significant-first, which is the whole reason it was added.
ULID drops four letters and ignores case
Crockford Base32 leaves out I, L, O and U — the first three so they cannot be mistaken for 1 and 0, the last to avoid spelling accidental words — so a ULID is safe to read aloud or drop into a URL. It is also case-insensitive: upper and lower spell the same value, unlike a KSUID or NanoID, where case carries information.
An ObjectId only knows the second
ObjectId timestamps are four bytes of whole seconds, so two documents inserted in the same second tie on time and fall back to a per-process counter for order. Those four bytes also roll over in 2106 — the same ceiling every 32-bit second counter shares — which is distant but real, not theoretical.
Time-sortable does not mean text-sortable
A Snowflake sorts by time only as a number: compared as strings, “9” comes after “10”, so a naive text sort scrambles them. A ULID sidesteps the trap because fixed-width Base32 sorts identically as text or as bytes. Match the comparison to the format — integer for Snowflake, text for ULID and KSUID, bytes for UUIDv6, UUIDv7 and ObjectId.
KSUID and NanoID are here for comparison only
This hub generates UUID, ULID, Snowflake and ObjectId; KSUID and NanoID appear as rows so you can weigh their size and entropy, but there is no generator for them here. A KSUID trades one extra character for 128 random bits over a 2014 epoch; a NanoID is 21 configurable characters with no timestamp at all.
Common errors
A Snowflake ID loses its last digits when parsed as a JSON number- JSON and JavaScript numbers are 64-bit floats with only 53 bits of integer precision, but a Snowflake needs all 64. Parse 175928847299117063 as a number and it silently becomes 175928847299117060 — now wrong, and pointing at nothing. Carry Snowflakes as strings from the database to the browser, or read them with BigInt.
Decoding a Snowflake with the wrong epoch- A Snowflake's timestamp is an offset from a platform epoch, and platforms disagree: Twitter counts from 1288834974657 and Discord from 1420070400000. The same 64-bit value reads as a 2012 date under Twitter's epoch and a 2016 date under Discord's, so a decoded time is meaningless unless you know which service minted the ID.
Expecting UUIDv1 to sort in chronological order- Because v1 carries a timestamp it looks like it should sort by time, but the spec splits the clock across three fields and puts the low bits first, so ordering by text or bytes comes out effectively random. UUIDv6 reorders those exact bits to sort correctly, and UUIDv7 leads with a plain millisecond field — reach for either when order matters.
FAQ
Is a ULID just a shorter UUID?
They share a size — 128 bits — but little else. A ULID writes those bits as 26 Crockford-Base32 characters with a 48-bit millisecond timestamp in front, so it is case-insensitive and sorts by creation time. A UUID writes them as 36 hyphenated hex characters and, apart from v6 and v7, carries no order. Same width, different alphabet, different guarantees.
Should I pick UUIDv7 or ULID for a time-sortable key?
Both lead with a 48-bit millisecond clock, so both sort by creation time and keep a database index compact under heavy inserts. Choose UUIDv7 to stay inside the UUID standard and your database's native uuid type; choose ULID for the shorter, URL-friendly, case-insensitive text. The deciding factor is usually whether your stack already speaks UUID.
Why does a Snowflake break when it reaches JavaScript?
A Snowflake is a full 64-bit integer, but JavaScript numbers — and JSON numbers — hold only 53 bits exactly, so the largest Snowflakes drop their final digits and change value without warning. The fix is to never let one become a number: keep it a string across the API boundary, and use BigInt if you genuinely must do arithmetic on it.
Which of these formats can I read a timestamp back out of?
Seven of the nine. UUIDv1, UUIDv6, UUIDv7, ULID and Snowflake each embed a millisecond-or-finer creation time, and ObjectId and KSUID embed whole seconds. UUIDv4 and NanoID embed none — they are pure randomness, so there is nothing to decode. The table's timestamp column marks which is which at a glance.
UUID or MongoDB ObjectId for a primary key?
An ObjectId is 12 bytes with a second-resolution timestamp, made client- or server-side, and native to MongoDB — on Mongo it is the path of least resistance. A UUID is 16 bytes and portable to any database and language. Off MongoDB a UUID travels better, and UUIDv7 gives you the same rough time-ordering an ObjectId has.
Is there one command that prints every ID format?
No single command covers them all. The line on this page, python -c "import uuid; print(uuid.uuid4())", prints one random UUIDv4, and the system uuidgen does much the same; ULIDs, Snowflakes and ObjectIds each need their own library or the live panels above. For a real value use the panels; the command is only a quick check of a single format.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Generate a fresh sample