ULID Generator
Generate ULIDs (Universally Unique Lexicographically Sortable Identifiers) online. Single or batch up to 100. Shows timestamp and random components. Built-in ULID decoder. Runs in your browser, no dependencies.
- Runs in your browser
- Your data never leaves your browser
- Free · No Sign-Up
Scan with WeChat to share this tool
Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.
ULID Structure
01ARZ3NDEKTSV4RRFFQ69G5FAV
├─ Timestamp (10 chars) ──┤├── Randomness (16 chars) ──┤
48-bit ms since epoch 80 bits: random, or previous + 1
Each character carries 5 bits in Crockford Base32 (0123456789ABCDEFGHJKMNPQRSTVWXYZ). Ten characters hold 50 bits,
two more than the 48-bit timestamp needs, which is why the first character can only be 0–7. The random part comes from
crypto.getRandomValues; within one millisecond it is the previous value plus one (see the batch example below).
Examples
The values below are produced by the tool’s own generator and decoder functions.
Decoding a ULID
| Input | Timestamp | Milliseconds (epoch) |
|---|---|---|
01ARZ3NDEKTSV4RRFFQ69G5FAV (example from the ULID spec) | 2016-07-30 23:54:10.259 UTC | 1469922850259 |
7ZZZZZZZZZZZZZZZZZZZZZZZZZ (largest ULID) | +010889-08-02 05:31:50.655 UTC | 281474976710655 |
8ZZZZZZZZZZZZZZZZZZZZZZZZZ | Out of range: the first character must be 0–7 | |
01ARZ3NDEKTSV4RRFFQ69G5FAL | Invalid ULID (L is not in the alphabet) | |
The decoder trims spaces and accepts lowercase. The milliseconds value is what Date.now() returned when the ULID was
made, so you can paste it into the Timestamp Converter to see it in your own time zone.
The decoder reads only the first 10 characters; the random part carries no information to decode.
A batch inside one millisecond
Generating three ULIDs at 2026-10-01 09:30:00.123 UTC gives a shared timestamp prefix 01M3VCS7HV. Only the first random
part is drawn from the random number generator; the next two add 1 to it:
01M3VCS7HV28T5CY4TQKFF049201M3VCS7HV28T5CY4TQKFF049301M3VCS7HV28T5CY4TQKFF0494
If the system clock moves backwards, for example after an NTP correction, the generator keeps the last timestamp and keeps counting,
so a later ULID never sorts before an earlier one from the same page. This is the behaviour the ULID spec describes under
Monotonicity and that monotonicFactory() in the reference JavaScript library implements. ULIDs from different browsers
or servers in the same millisecond are not ordered among themselves; only their timestamps are.
ULID vs UUID Comparison
| Feature | ULID | UUID v4 |
|---|---|---|
| Length | 26 chars | 36 chars (with dashes) |
| Sortable | ✓ Yes | ✗ No |
| Timestamp-embedded | ✓ Yes | ✗ No |
| URL-safe | ✓ Yes | ✓ Yes |
| Case-insensitive | ✓ Yes | ✓ Yes |
| Randomness bits | 80 | 122 |
Why Sort Order Matters in Databases
With random UUIDs as primary keys in a B-tree index (PostgreSQL, MySQL InnoDB), each insert lands at a random place in the index,
which splits pages and spreads writes across the whole index. ULIDs created later sort later, so inserts go to the right edge of the
index, as they would with an auto-increment column. The same holds for UUID version 7 (RFC 9562 section 5.7), which also starts with
a 48-bit millisecond timestamp and fits a native uuid column, while a ULID is usually stored as a 26-character string or
as 16 bytes after decoding.
Keep in mind that the timestamp is readable by anyone who sees the ID: a public ULID tells the reader when the record was created. If that is a problem, use a random UUID v4 for public identifiers.
Limitations
- At most 100 ULIDs per click. A count above 100 is treated as 100; below 1, empty or non-numeric counts give 1.
- The decoder accepts only the 32 letters and digits of the alphabet. Crockford’s Base32 also allows reading
IandLas 1 andOas 0, but the decoder rejects these letters as an invalid ULID rather than guessing. - There is no option for lowercase output or for converting a ULID to a UUID string or 16 raw bytes.
- If the random part reaches
ZZZZZZZZZZZZZZZZwithin one millisecond, generation stops with the message “The random part overflowed within one millisecond” instead of wrapping around. With a random starting point this needs on the order of 279 ULIDs in one millisecond, so in practice it does not happen.
Related Tools
- UUID Generator — generate standard UUID v4 identifiers
- Nano ID Generator — short random IDs without a timestamp
FAQ
What is a ULID?
ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier represented as 26 characters in Crockford Base32. Unlike UUID v4, ULIDs are monotonically sortable — they encode a 48-bit millisecond timestamp followed by 80 bits of randomness. This means ULIDs sort chronologically by default.
How is a ULID structured?
A ULID is 26 characters long: the first 10 characters encode the timestamp (48 bits, millisecond precision, valid until year 10889), and the remaining 16 characters carry 80 random bits from crypto.getRandomValues, except that within the same millisecond each new ULID takes the previous random part plus 1. The encoding uses Crockford Base32: 0-9 and A-Z excluding I, L, O, U to avoid visual ambiguity.
How does ULID compare to UUID?
UUID v4 is entirely random and does not sort chronologically. ULIDs sort lexicographically in creation order, which makes them much better for database primary keys — inserting in order reduces B-tree fragmentation and improves query performance on range scans. ULIDs are also URL-safe and case-insensitive.
What is the ULID decoder for?
Paste an existing ULID to extract its creation timestamp. This is useful for debugging — you can determine exactly when a record was created directly from its ID without a separate created_at column. The decoder accepts upper or lower case and rejects a ULID whose first character is above 7: the largest ULID is 7ZZZZZZZZZZZZZZZZZZZZZZZZZ, and anything larger does not fit in 128 bits (ULID spec, Overflow Errors when Parsing Base32 Strings).
Are the ULIDs in one batch in order?
Yes. A batch is usually generated within one millisecond, so the ULIDs share a timestamp. As the ULID spec's monotonicity section describes, each one after the first adds 1 to the random part of the one before, so the list is already sorted: …EMMVRZ is followed by …EMMVS0. A new millisecond starts from fresh random bits. If the random part would pass ZZZZZZZZZZZZZZZZ within one millisecond, generation stops with an error instead of wrapping around.
Are generated or decoded ULIDs sent anywhere or saved?
No. Generation uses the browser's Web Crypto API (crypto.getRandomValues) and Date.now(), and decoding runs in the same page; the ULIDs you generate or paste are not sent to ZeroTool, and the tool keeps neither the ULIDs nor its settings after you leave the page. Google Analytics on the page records which action was used (generate, decode, copy), without the ULID values.