ksuid.net
Back

ulid generator

Recommended

Click on an ID to copy.

PropertyValue
Bit Length128
Output Length26 chars
EncodingCrockford base32
SortableYes
TimestampedYes
MonotonicYes
Crypto RandomYes

ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit unique identifier format created by Alizain Feerasta in 2016 as a modern alternative to UUID that combines global uniqueness with chronological sortability. The format was designed to address the most common frustrations developers face with traditional UUIDs: random UUIDs (v4) produce fragmented database indexes because their values are uniformly distributed, and none of the original UUID versions encode a sortable timestamp that preserves creation order. ULID solves both problems by placing a millisecond-precision timestamp in the most significant bits and filling the remaining bits with cryptographically secure randomness. The result is an identifier that is globally unique, lexicographically sortable, and efficient for database indexing -- all encoded in a compact 26-character Crockford base32 string.

The ULID specification quickly gained traction across the software development community because it addressed a real and widespread need. As microservice architectures and distributed databases became mainstream, developers increasingly needed identifiers that could be generated independently on any node while still maintaining a meaningful, sortable order. UUIDs provided uniqueness but not sortability. Snowflake IDs provided sortability but required worker-ID coordination. ULID provided both with no coordination at all. Today, ULID implementations exist in virtually every major programming language, and the format has influenced subsequent standards including UUID v7, which adopted ULID's core idea of timestamp-prefixed random identifiers into the formal UUID specification.

How ULID Works

A ULID is a 128-bit value divided into two contiguous sections with no version bits, variant markers, or reserved fields.

The high 48 bits encode a Unix timestamp in milliseconds, providing roughly 8,919 years of range from the Unix epoch. The timestamp is stored in big-endian byte order, ensuring that ULIDs generated at later times always have numerically larger values than those generated earlier.

The low 80 bits are filled with data from a cryptographically secure pseudorandom number generator (CSPRNG). Eighty bits of randomness provide approximately 1.2 x 10^24 possible values per millisecond window, making collisions vanishingly unlikely even at high generation rates. This randomness is the sole mechanism for uniqueness -- there are no worker IDs, node identifiers, or sequence counters to configure or coordinate.

The canonical string representation uses Crockford's base32 encoding, which maps the 128-bit value to exactly 26 characters using an alphabet of 10 digits and 22 uppercase letters (I, L, O, and U are excluded to avoid visual ambiguity). The encoding is case-insensitive by specification. Of the 26 characters, the first 10 encode the 48-bit timestamp and the remaining 16 encode the 80-bit random component.

Because the timestamp occupies the most significant bits and Crockford base32 preserves sort order, lexicographic comparison of ULID strings produces the same ordering as chronological comparison of creation times. This means a simple ORDER BY id clause in a database query sorts records by creation time without requiring a separate timestamp column.

The ULID specification also defines an important optional extension: monotonic ULIDs. In standard mode, two ULIDs generated within the same millisecond receive independent random components and are ordered randomly relative to each other. In monotonic mode, the generator detects when the current millisecond matches the previous generation's millisecond and increments the random component by one instead of generating a new random value. This guarantees strict ordering within the same millisecond on the same generator. If the random component overflows, the generator waits for the next millisecond tick. Monotonic mode is critical for applications that require total ordering, such as event sourcing systems or append-only logs.

The generation algorithm is simple and efficient. The generator reads the current Unix time in milliseconds, places it in the upper 48 bits, fills the lower 80 bits with random data (or increments them in monotonic mode), and encodes the result as a 26-character Crockford base32 string. The entire operation involves no disk I/O, no network calls, and no inter-process coordination.

Use Cases

Database primary keys in distributed systems. ULID's most compelling use case is as a primary key in databases where multiple application instances independently create records. Because ULIDs are time-ordered, new inserts append to the end of B-tree indexes rather than landing at random positions, dramatically reducing index fragmentation and improving write performance compared to random UUIDs. This benefit is especially pronounced in write-heavy workloads on PostgreSQL, MySQL, and CockroachDB.

Event sourcing and message ordering. Event-sourced architectures append immutable events to a log and replay them in order to reconstruct application state. ULID is a natural fit for event identifiers because each event's ULID encodes its creation time and sorts correctly among all other events. The monotonic extension ensures that events generated in rapid succession on the same node maintain their exact creation order, which is essential for deterministic replay.

API resource identifiers. ULIDs make excellent public-facing identifiers in REST and GraphQL APIs. At 26 characters, they are shorter than hyphenated UUIDs (36 characters), contain no special characters, and are safe for URLs without encoding. Their case-insensitivity reduces errors when identifiers are communicated verbally. And because they are sortable, API consumers can paginate results using ULID-based cursors without server-side translation.

Log correlation and distributed tracing. In observability systems that aggregate logs from many services, ULID-based trace and span IDs provide both uniqueness and temporal context. An engineer debugging an incident can sort trace IDs lexicographically to see the chronological flow of events across services. The embedded timestamp also enables efficient time-range queries on log storage systems that index by identifier.

Comparison with Alternatives

ULID and UUID v7 share the same fundamental design: millisecond timestamp in the high bits, randomness in the low bits. The key difference is standardization. UUID v7 is defined in RFC 9562 and conforms to the UUID format with version and variant bits, making it recognized as a valid UUID by any UUID-aware library or database driver. ULID uses all 128 bits for timestamp and randomness without version or variant markers, giving it more randomness (80 bits versus approximately 62 bits) and a more compact string representation (26 characters versus 36). Choose UUID v7 when ecosystem compatibility with UUID tooling is essential; choose ULID when you want a more compact string and more random bits.

Compared to KSUID, ULID offers finer timestamp granularity but a smaller total size. KSUID uses a 32-bit second-precision timestamp with 128 bits of randomness, totaling 160 bits in 27 base62 characters. ULID uses a 48-bit millisecond timestamp with 80 bits of randomness, totaling 128 bits in 26 Crockford base32 characters. KSUID's larger random component provides stronger collision resistance, while ULID's millisecond precision provides better time-ordering resolution and its 128-bit size is compatible with UUID column types. Choose ULID for millisecond-level ordering and UUID-column compatibility; choose KSUID for maximum collision resistance.

When compared to SCRU128, ULID is simpler but less precisely ordered. SCRU128 is also 128-bit and timestamp-based, but it uses a 44-bit millisecond timestamp supplemented by a 28-bit sub-millisecond counter and 56 bits of randomness. This guarantees strict monotonic ordering even within the same millisecond, without the random-component increment approach of ULID's monotonic mode. For applications where absolute monotonic ordering is non-negotiable, SCRU128 provides a stronger guarantee. For general-purpose use where broader ecosystem adoption matters, ULID remains the more popular choice.

Code Examples

import { ulid } from 'ulid';
const id = ulid();
console.log(id); // 01ARZ3NDEKTSV4RRFFQ69G5FAV

Frequently Asked Questions

What is a ULID?

A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier that combines a 48-bit millisecond timestamp with 80 bits of cryptographic randomness. ULIDs are designed to be a drop-in replacement for UUIDs while adding the benefit of lexicographic (alphabetical) sortability by creation time.

How does ULID differ from UUID?

While both ULID and UUID are 128-bit identifiers, ULIDs embed a timestamp that makes them naturally sortable by creation time, whereas UUID v4 values are entirely random. ULIDs also use a more compact Crockford Base32 encoding (26 characters) compared to UUID hex encoding (36 characters with hyphens).

Is ULID sortable by creation time?

Yes, ULIDs are lexicographically sortable by creation time. The first 10 characters of a ULID string encode the millisecond timestamp, so sorting ULIDs alphabetically also sorts them chronologically. This property makes ULIDs ideal for database primary keys and event logs where insertion order matters.

What encoding does ULID use?

ULID uses Crockford Base32 encoding, which represents the 128-bit value as a 26-character string using the digits 0-9 and uppercase letters excluding I, L, O, and U. This encoding is case-insensitive, avoids visually ambiguous characters, and is URL-safe without any special characters.

Can I extract the timestamp from a ULID?

Yes, the timestamp is encoded in the first 48 bits (10 characters) of a ULID and can be easily extracted. Most ULID libraries provide a built-in method to decode the creation timestamp as a Unix epoch millisecond value or a Date object, making ULIDs useful for auditing and debugging.

Comparisons Featuring ULID

Related Generators

© 2024 Carova Labs. All rights reserved