ULID Generator & Decoder
Generate ULIDs — compact, URL-safe, lexicographically sortable IDs — and decode their timestamp. Runs entirely in your browser.
How to use ULID Generator
- 1Choose how many
Set how many ULIDs to generate (1–100).
- 2Generate
Click Generate. The random portion is created locally with your browser crypto API.
- 3Copy
Copy a single ULID or use Copy all for the batch.
- 4Decode (optional)
Paste a ULID into the decoder to read the timestamp in its first 10 characters.
About ULID Generator
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit ID designed to be globally unique and sortable by creation time, while staying more compact and URL-friendly than a UUID. The specification describes it as "canonically encoded as a 26 character string, as opposed to the 36 character UUID" — for example 01ARZ3NDEKTSV4RRFFQ69G5FAV — with no hyphens or special characters, so it drops cleanly into URLs, filenames, and database keys.
The structure has two parts: the first 10 characters encode a 48-bit Unix millisecond timestamp, and the remaining 16 characters carry 80 bits of randomness. The timestamp coming first is only half of what makes a ULID sortable, though. The other half is the alphabet: sorting text gives you creation order only if the characters rank in the same order as the values they represent, and Crockford Base32 is built that way — all 32 of its symbols have strictly ascending character codes. Pack the same 128-bit payloads into base64url instead and the sort falls apart, because that alphabet runs A–Z, a–z, 0–9, then two punctuation marks, which is nothing like their character-code order.
Sorting also needs the generator to handle values created inside the same millisecond, where the timestamp prefix is identical. The spec is specific about this: "if the same millisecond is detected, the random component is incremented by 1 bit in the least significant bit position (with carrying)." Draw fresh randomness each time instead and a same-millisecond batch comes out shuffled — which is what this generator did until we measured it. At 100 values in a single millisecond, 50 of the 99 adjacent pairs were out of order. It now increments as the spec describes, and batches of 5, 100, 1,000, and 20,000 measured zero inversions against generation order.
Crockford Base32 omits I, L, and O because they are confusable with 1 and 0, and U to avoid accidental obscenity — but the decoder is meant to be forgiving about exactly that: "upper and lower case letters are accepted, and i and l will be treated as 1 and o will be treated as 0", with hyphens "ignored during decoding". That forgiveness is the point of the readable alphabet, so the decoder here implements it and shows you the canonical form it resolved to. It also enforces the spec's ceiling: 26 Base32 characters can hold 130 bits, two more than a ULID has, so "the largest valid ULID encoded in Base32 is 7ZZZZZZZZZZZZZZZZZZZZZZZZZ" and anything above it is rejected rather than silently decoded into a nonsense date.
ULIDs suit sortable, decentralised IDs that need a friendlier text form than a UUID: public-facing resource identifiers, log and event IDs, distributed primary keys. The main alternative is UUID v7, which offers the same time-ordering inside the standard UUID format — pick ULID when compactness and readability matter, and v7 when you need to stay in a native UUID column. Everything runs in your browser through the Web Crypto API; nothing you generate or decode is ever sent to a server.
ULID and UUID v7 solve the same problem with different encodings
Both are 128 bits with a 48-bit millisecond timestamp in front, so the interesting differences are in how they spend the remaining bits, how they survive being written down, and what a database column does with them. The v7 column describes this site's generator specifically, since the RFC leaves the same-millisecond scheme up to the implementation:
| ULID | UUID v7 (as generated here) | |
|---|---|---|
| Canonical text form | 26 characters, Crockford Base32, no hyphens | 36 characters including four hyphens, lowercase hex |
| Same-millisecond ordering | The spec increments the 80-bit random component "by 1 bit in the least significant bit position (with carrying)" | A 12-bit dedicated counter in rand_a — method 1 of RFC 9562 §6.2 |
| Collision resistance between two independent generators in the same millisecond | 80 bits — roughly 1.29 trillion values before a 50% chance of any collision | 62 bits, because 12 are set aside for the counter — roughly 2.53 billion on the same basis |
| Values that look valid but are not | 26 Base32 characters hold 130 bits, so strings above 7ZZZZZZZZZZZZZZZZZZZZZZZZZ parse but overflow the 48-bit timestamp and must be rejected | None from overflow — 128 bits map exactly onto 32 hex digits |
| Typed or read back by a human | Case-insensitive, I and L decode as 1, O as 0, hyphens ignored | Case-insensitive hex, with no provision for confusable characters |
| What the database stores | Text — CHAR(26) or similar, compared as a string | A native uuid type on PostgreSQL, BINARY(16) on MySQL |
Either scheme only sorts if the stored representation orders the same way the underlying bytes do, and that is a property of the encoding rather than of the ID. The 32 symbols of Crockford Base32 have strictly ascending character codes, so a plain string sort over a ULID column matches timestamp order — checked against 400 ULIDs generated a millisecond apart, where string order matched creation order for every one of them. The collision figures are for two generators racing in the same millisecond: a single generator cannot collide with itself once it orders same-millisecond values, because each one is derived from the last rather than drawn independently.
When to use ULID Generator
- Sortable database keys
Time-ordered keys keep index inserts sequential while remaining globally unique.
- Public resource IDs
Shorter and hyphen-free, ULIDs slot into URLs and filenames without escaping.
- Log and event ordering
Sort records by ULID as plain strings to get them in creation order.
- Timestamp recovery
Decode a ULID to read its creation time without a separate timestamp field.
Four ULID mistakes — three of which this tool was making
- Assuming a more compact encoding keeps the IDs sortable
Sortability needs an alphabet whose character order matches its value order, and shortening an ID by re-encoding it can quietly destroy that. We packed 400 identical 128-bit payloads, timestamps one millisecond apart, into Crockford Base32 and into base64url, then sorted the strings as text. Crockford order matched creation order for all 400. Base64url went wrong at the very first position — it sorted a timestamp ending 062 ahead of one ending 052 — and across the sorted list 3,648 of the 79,800 possible pairs, or 4.6%, had their timestamps inverted. The cause is the alphabet: base64url indexes A–Z, then a–z, then 0–9, then two punctuation marks, while character codes put digits before uppercase and uppercase before lowercase.
Crockford: 0123456789ABCDEFGHJKMNPQRSTVWXYZ → codes ascend, sort works base64url: A–Z a–z 0–9 - _ → codes do not ascend, sort breaks - Trusting that any 26-character Base32 string is a valid ULID
Twenty-six Base32 characters carry 130 bits and a ULID only uses 128, so the first character can legally reach 7 and no further. The spec names the ceiling — "the largest valid ULID encoded in Base32 is 7ZZZZZZZZZZZZZZZZZZZZZZZZZ, which corresponds to an epoch time of 281474976710655 or 2 ^ 48 - 1" — and asks implementations to reject anything above it "to prevent overflow bugs". Our decoder did not: it read 8ZZZZZZZZZZZZZZZZZZZZZZZZZ as a date in the year 12004, and a string of 26 Zs as the year 37648, both delivered with no warning at all. It now refuses them and still accepts 7ZZZ… on the nose, which decodes to August of 10889.
- Rejecting the characters Crockford designed to be forgiven
The alphabet leaves out I, L, O, and U so that IDs survive being read aloud and retyped, and Crockford's decoding rules finish the job: "upper and lower case letters are accepted, and i and l will be treated as 1 and o will be treated as 0", while hyphens inserted for readability are "ignored during decoding". Our decoder handled lowercase and then rejected everything else in that list — an O typed for a zero, an I or L typed for a one, a hyphen added to break up the string. All four now resolve to the same canonical value, and the tool prints the form it resolved to so you can see what it read. U stays invalid, which is deliberate: Crockford excludes it to avoid accidental obscenity.
01ARZ3NDEK-TSV4RRFFQ69G5FAV hyphen ignored 01arz3ndektsv4rrffq69g5fav case-insensitive O1ARZ3NDEKTSV4RRFFQ69G5FAV O reads as 0 → all decode to 01ARZ3NDEKTSV4RRFFQ69G5FAV, 2016-07-30T23:54:10.259Z - Expecting same-millisecond order without the monotonic behaviour
Drawing 80 fresh random bits for every ULID leaves values created inside one millisecond in arbitrary order, and a batch is exactly where that bites. Generating 100 at once landed them all in a single millisecond and put 50 of the 99 adjacent pairs out of order, with 2,605 of the 4,950 possible pairs inverted — 52.6%, a coin flip, as expected when the tiebreak is random. Note that the all-pairs figure depends on how many milliseconds a batch happens to span, since pairs from different milliseconds always sort correctly; the invariant is that same-millisecond pairs land at roughly 50%. Incrementing the random component as the spec prescribes fixed it: zero inversions at 5, 100, 1,000, and 20,000 values. The two specifications prescribe different remedies for the identical problem — ULID increments its whole random field, while RFC 9562 gives UUID v7 a short dedicated counter, which our UUID v7 generator covers in more depth.
Frequently asked questions
What is the difference between a ULID and a UUID?+
Both are 128-bit unique IDs, but a ULID is 26 Crockford Base32 characters and time-sortable by design, while a UUID v4 is 36 characters and fully random. The closest comparison is UUID v7, which also leads with a 48-bit millisecond timestamp — ULID is shorter and friendlier to type, v7 fits a native UUID column.
Are ULIDs sortable?+
Across milliseconds, always. Within a single millisecond, only if the generator increments the random component instead of redrawing it — this one does, and the line under the output re-checks the batch on screen. The other requirement is the encoding: a string sort only matches byte order because the 32 Crockford symbols have strictly ascending character codes. Re-encode the same IDs in base64url and sorting no longer tracks creation time.
What is the largest valid ULID?+
7ZZZZZZZZZZZZZZZZZZZZZZZZZ, which the specification ties to "an epoch time of 281474976710655 or 2 ^ 48 - 1" — August of the year 10889. Twenty-six Base32 characters can hold 130 bits, two more than a ULID uses, so larger strings are well-formed Base32 but not valid ULIDs; the decoder above rejects them instead of returning a far-future date.
What characters can appear in a ULID?+
Crockford Base32: digits 0–9 and uppercase letters excluding I, L, O, and U. I, L, and O are left out because they are confusable with 1 and 0; U is left out to avoid accidental obscenity. The result is URL- and filename-safe with no escaping.
Can I type a ULID with an O instead of a zero?+
Yes, in the decoder above. Crockford Base32 specifies that on decoding, I and L are read as 1 and O is read as 0, that case does not matter, and that hyphens are ignored — so all of those resolve to the same ULID, and the tool shows the canonical form it arrived at. Generated ULIDs never contain those characters, so the canonical form is what you should store.
Can I recover the creation time from a ULID?+
Yes. The first 10 characters encode a Unix millisecond timestamp; paste a ULID into the decoder above to read it. That also means the creation time is readable by anyone holding the ID, which is the trade-off ULID shares with UUID v7.
Is generation secure and private?+
The random component comes from your browser cryptographically secure generator — 80 bits, or roughly 1.29 trillion values within one millisecond before a 50% chance of any collision. Everything runs locally; no ULID is sent to any server.
Related tools
Generate time-ordered UUID v7 identifiers and decode their embedded timestamp. Free, fast, runs entirely in your browser.
Generate compact, URL-safe Nano IDs with a custom length. Cryptographically secure, runs entirely in your browser.
Generate cryptographically random UUID v4 identifiers — single or bulk, instantly.