UUID vs ULID vs Nano ID: Size, Sorting and Collisions
Last updated Published by Hyperdusk Ltd
The short answer
A UUID is a 128-bit identifier standardised in RFC 9562 and written as 36 characters. A ULID is also 128 bits, with a millisecond timestamp first, written as 26 characters. A Nano ID is a random string, 21 characters by default, carrying 126 random bits. UUID v7 and ULID sort by creation time; UUID v4 and Nano ID do not.
Generate UUID v4 and v7 values online →Key differences
| UUID v4 | UUID v7 | ULID | Nano ID | |
|---|---|---|---|---|
| Specified by | RFC 9562 | RFC 9562 | The ulid/spec repository | The Nano ID library's README |
| Size | 128 bits | 128 bits | 128 bits | 126 bits by default |
| Text length | 36 | 36 | 26 | 21 by default |
| Alphabet | Hex digits and hyphens | Hex digits and hyphens | Crockford base32: no I, L, O or U | A-Z, a-z, 0-9, _ and - |
| Bits per character | 4 | 4 | 5 | 6 |
| Timestamp | None | 48-bit Unix ms | 48-bit Unix ms | None |
| Random bits | 122 | Up to 74 | 80 | 126 |
| Sorts by creation time | No | Yes | Yes | No |
| Case-sensitive | No | No | No | Yes |
What is a ULID?
ULID stands for Universally Unique Lexicographically Sortable Identifier. Its specification is a README in the ulid/spec repository on GitHub, not a standards document. A ULID is 128 bits: a 48-bit Unix timestamp in milliseconds followed by 80 bits of randomness. The spec says the timestamp will not run out until the year 10889.
It is written as 26 characters of Crockford's base32, which leaves out I, L, O and U to avoid confusion and is case-insensitive. Because the timestamp comes first, ULIDs sort by creation time as plain text. Within the same millisecond the spec says sort order is not guaranteed unless the generator is monotonic, in which case it increments the random part by one for each new ID.
A ULID is the same size as a UUID and its first 48 bits mean the same thing as a UUID v7's. It does not reserve the version and variant bits that RFC 9562 requires, so a ULID stored in a UUID column is not a valid UUID v7.
What is a Nano ID?
Nano ID is a JavaScript library that describes itself as "a tiny, secure, URL-friendly, unique string ID generator". By default it returns 21 characters drawn from a 64-symbol alphabet: A-Z, a-z, 0-9, underscore and hyphen. At 6 bits per character that is 126 random bits, which its README compares with the 122 in a UUID v4.
There is no timestamp and no internal structure, so Nano IDs do not sort by time. Both the length and the alphabet can be changed. The README warns that a shorter ID raises the collision probability and links a calculator for checking a custom size.
Which of them sort by creation time?
UUID v7 and ULID. Both put a 48-bit millisecond timestamp in the most significant bits, so comparing two IDs as text or as bytes compares their creation times first. UUID v4 and Nano ID are random throughout and have no order.
Ordering matters most for database keys. RFC 9562 says that UUIDs which are not time-ordered have poor database index locality, because new values are inserted at random positions in the index. The RFC lists ULID among the earlier time-ordered formats it reviewed when defining v7.
The cost of a leading timestamp is that every ID shows when it was created.
How do the collision odds compare?
For the two random formats, what matters is the total number of IDs ever generated. For the two time-ordered formats, only IDs created in the same millisecond can collide, so what matters is the generation rate.
| Format | Random bits | IDs for a 1-in-a-billion chance | IDs for a 50% chance |
|---|---|---|---|
| UUID v4 | 122 | 1.03 × 10^14 in total | 2.71 × 10^18 in total |
| Nano ID (21 characters) | 126 | 4.12 × 10^14 in total | 1.09 × 10^19 in total |
| UUID v7 | 74 | 6.15 million in one millisecond | 1.62 × 10^11 in one millisecond |
| ULID | 80 | 49.2 million in one millisecond | 1.29 × 10^12 in one millisecond |
At ordinary generation rates none of the four is a practical risk. The figures only hold with a cryptographically secure random source.
Which is shortest in a URL or a database?
As text, a Nano ID is 21 characters, a ULID is 26 and a UUID is 36. In binary, a UUID and a ULID are both 16 bytes. A Nano ID is a string and is stored as one.
UUIDs have built-in database support: PostgreSQL, for example, has a native uuid column type and functions that generate v4 and v7. ULID and Nano ID come from libraries, so the application generates them and the database sees text or bytes.
A ULID can be read aloud or typed without worrying about case. A Nano ID cannot, because a and A are different characters in its alphabet.
Which should you use?
Use UUID v7 when you want a time-ordered key that follows a published standard and that databases can generate and store natively. Use UUID v4 when the ID should carry no timestamp and you still want a standard format.
Use ULID when you need time ordering in a shorter, case-insensitive string and a library for your language is acceptable. Use Nano ID for short, URL-safe identifiers that are handled as strings and never need to sort, such as share links or client-side keys.
Tools for this
- Generate UUID v4 and v7 values online →
UUID Generator. Generates v4, v7 and v1 UUIDs and decodes pasted ones. It does not generate ULIDs or Nano IDs.
Sources
This page was written from the primary sources below, read on .
- RFC 9562: Universally Unique IDentifiers (UUIDs)
IETF. UUID v4 and v7 layouts, text format, the index-locality rationale and the list of earlier formats reviewed.
- ULID specification
ulid/spec on GitHub. The 48-bit timestamp and 80-bit randomness layout, Crockford base32 encoding, sorting and monotonicity rules.
- Nano ID README
ai/nanoid on GitHub. Default length and alphabet, the 126-bit comparison with UUID v4, and the custom size and alphabet options.
- PostgreSQL 18: UUID Functions
PostgreSQL Global Development Group. Native uuidv4() and uuidv7() generation.