ULID Generator — Sortable, Timestamp-Based Unique IDs Online

ULID Generator

Conditions

Results

1

About the ULID Generator

Overview

A random UUID makes a fine unique key, but it tells you nothing about when a row was created and it wrecks B-tree index locality at scale — every insert lands in a random page. ULID (Universally Unique Lexicographically Sortable Identifier, per the ulid/spec) solves both problems by combining a millisecond timestamp with random bits, so IDs sort chronologically as plain strings. This tool generates ULIDs in bulk, with control over the base timestamp and strict monotonic ordering, as a drop-in alternative wherever you'd reach for a UUID.

UUID v4 is a solid identifier on its own merits, but its randomness works against it as a primary key — insertion order and sort order have no relationship, so B-tree indexes fragment as rows accumulate. Embedding a millisecond-precision timestamp up front is what fixes that, while keeping collision resistance on par with a UUID. Generation happens entirely in the browser, so you can pull a whole batch at once without any data leaving your machine.

How to Use

  1. 1Set Number of ULIDs to the batch size you need.
  2. 2Set the Base datetime - Timestamp field to the millisecond timestamp you want encoded (defaults to now). Use the "Select datetime" tooltip to open a picker, or "Reload" to snap it back to the current time.
  3. 3Toggle Increase monotonically on if you need a guaranteed, strictly increasing order across the batch, even for entries that share the same millisecond.
  4. 4Click Generate and copy the values out of the Results card.

Note: to issue a batch of ULIDs anchored to a specific past or future moment, set Base datetime - Timestamp to that date before generating. This is handy when you need to control the insertion order of seeded test data.

Specifications & Glossary

  • ULID layout: 128 bits total, split into a 48-bit millisecond timestamp and 80 bits of randomness, encoded as a fixed 26-character Crockford's Base32 string (e.g., 01ARZ3NDEKTSV4RRFFQ69G5FAV). Same bit width as a UUID, but the first 10 characters are time, not noise.
  • Lexicographic = chronological: Because the timestamp occupies the first 10 characters, a plain string sort (`ORDER BY id` in SQL, or `Array.sort()` in JS) puts ULIDs in creation order automatically — no separate `created_at` column needed just for ordering. As a side effect, sequential inserts land near each other in a B-tree index instead of scattering across random pages, which is the main reason ULID and similar schemes outperform UUID v4 as primary keys at scale.
  • Increase monotonically: Two ULIDs generated in the same millisecond would otherwise have unrelated random suffixes, so their relative order is arbitrary. With this switch on, the random part increments by one instead of re-rolling, so a batch generated in a tight loop still comes out in the exact order it was created — important for event logs where insertion order matters even at sub-millisecond resolution.
  • ULID vs. UUID v4: A UUID v4 is 122 bits of pure randomness (per RFC 4122) — sorting a column of them tells you nothing about insertion order, and clustered/B-tree indexes suffer from the resulting random write pattern. ULID keeps the same 128-bit footprint but front-loads a timestamp, so it behaves like a UUID for uniqueness while sorting like a sequential ID. If you control the schema, ULID (or UUID v7, below) is usually the better default for primary keys.
  • Crockford's Base32: The encoding alphabet deliberately drops I, L, O, and U — letters that are easily mistaken for 1, 1, 0, and V when read aloud or copied by hand. That makes ULIDs safer to transcribe in support tickets or log excerpts than a standard Base32 or hex string of the same length.
  • Collision probability: Even within the same millisecond, 80 bits of randomness keeps collisions vanishingly rare for practical purposes. Turn on Increase monotonically to eliminate duplicates within a single generation run entirely.
  • Recovering the timestamp: Decoding the first 10 characters (48 bits of Base32) hands back the exact millisecond Unix timestamp used at generation — handy for reconstructing when a log entry actually occurred.

Use Cases

  • Generating log or event IDs where the ID itself encodes "what happened first," even before you look at a timestamp column.
  • Replacing an auto-increment or UUID v4 primary key with something that's both globally unique and index-friendly.
  • Naming uploaded files or short-lived tokens with an identifier that sorts naturally in a file listing or S3 bucket.
  • Weighing ULID against UUID v7 (RFC 9562): both are time-ordered and sort correctly as strings, so the choice often comes down to format. ULID is a 26-character Base32 string with no separators and a community spec rather than an IETF standard; UUID v7 is the canonical 36-character hyphenated UUID format, so it slots into existing `uuid` database columns and client libraries without any schema changes. If you're already storing UUIDs everywhere, UUID v7 is usually the lower-friction upgrade; if you want shorter, URL-friendly IDs, ULID wins.
  • Distributed systems where multiple nodes issue IDs independently, but you still need sort order to roughly track when each ID was created.
  • Building test fixtures with several ULIDs spread across different timestamps, to verify a UI or query that relies on chronological ordering.

FAQ

What's the difference between ULID and UUID?
The biggest difference is sortability. UUID v4 is pure randomness, so string order and creation order have nothing to do with each other; ULID front-loads a 48-bit millisecond timestamp, so sorting the strings puts them back in roughly the order they were created. ULID is also shorter — 26 characters versus 36 for a hyphenated UUID.
Why does sorting ULIDs lexicographically put them in chronological order?
The first 10 characters are the milliseconds-since-epoch timestamp, Crockford's Base32-encoded so that the most significant digit sits leftmost — exactly how positional number systems already work. A later timestamp always produces a lexicographically larger prefix, so an ordinary string comparison sorts ULIDs chronologically with no special logic required.
Can I recover the creation timestamp from a ULID string?
Yes. Decode the first 10 characters as Crockford's Base32 and you get back the exact millisecond Unix timestamp used at generation time. The remaining 16 characters are pure randomness and carry no time information.
Can two generated ULIDs collide?
Not theoretically zero, but with 80 bits of randomness backing each ULID, collisions are negligible in practice. If you need a hard guarantee against duplicates and a strict order when generating several in the same millisecond, turn on Increase monotonically.
What changes when I enable Increase monotonically?
When several ULIDs share a millisecond, every one after the first increments the random portion by one instead of re-rolling it. That keeps the batch sorted in generation order even within a single timestamp, which matters for event logs where sequence has to be exact.
Can I migrate an existing UUID column to ULID?
Since a ULID is still a 128-bit value, it can be stored as raw bytes in a UUID-typed column, but the string representation looks different — no hyphens, a different alphabet — so swapping in ULIDs for existing UUID strings needs a conversion layer in your application code. Before migrating, check whether existing code assumes the 36-character hyphenated UUID string format anywhere.