ksuid.net
Back

ulidx generator

Recommended

Click on an ID to copy.

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

ULIDX is a modern, actively maintained TypeScript implementation of the ULID (Universally Unique Lexicographically Sortable Identifier) specification. Created as a successor to earlier ULID libraries, ULIDX provides full compliance with the ULID spec while adding critical features such as a monotonic factory, automatic timestamp detection, and first-class TypeScript support. The library was developed to address the maintenance gaps and missing features in the original ulid npm package, which had become stagnant. ULIDX produces the same 26-character, Crockford Base32-encoded identifiers as any other ULID implementation, meaning its output is fully interoperable with systems that already consume ULIDs. For teams working in TypeScript-heavy codebases that need time-sortable identifiers, ULIDX is the recommended library because it combines specification compliance with modern developer ergonomics.

The core value proposition of ULIDX is that it delivers everything the ULID specification promises while solving the practical problems developers encounter in production. The original ULID libraries often lacked monotonic ordering guarantees, had incomplete type definitions, or were no longer receiving security patches. ULIDX addresses all of these concerns in a single, lightweight package. It remains fully compatible with the ULID specification, so any system that reads or stores ULIDs can accept ULIDX-generated values without modification.

How ULIDX Works

ULIDX generates 128-bit identifiers that follow the exact structure defined in the ULID specification. Each identifier is composed of two segments: a 48-bit timestamp and an 80-bit random component.

The timestamp portion occupies the most significant 48 bits and encodes the number of milliseconds elapsed since the Unix epoch (January 1, 1970, 00:00:00 UTC). This 48-bit allocation provides coverage until approximately the year 10889, which is far beyond any practical planning horizon. Because the timestamp fills the leading bits, ULIDX values naturally sort in chronological order when compared as strings or byte arrays.

The randomness portion occupies the lower 80 bits and is filled using a cryptographically secure pseudo-random number generator (CSPRNG). This provides approximately 1.21 x 10^24 possible values per millisecond, making collisions statistically negligible for virtually any workload.

The combined 128-bit value is encoded using Crockford's Base32 alphabet, which excludes visually ambiguous characters such as I, L, O, and U. This encoding produces a fixed-length, 26-character string that is URL-safe, case-insensitive, and free of special characters. The first 10 characters represent the timestamp, and the remaining 16 characters represent the randomness.

Where ULIDX distinguishes itself from basic ULID implementations is its monotonic factory. In the standard ULID algorithm, two identifiers generated within the same millisecond receive independent random components, which means their relative order is unpredictable. The monotonic factory solves this by incrementing the random component of the previous ULID when the timestamp has not advanced. This guarantees that identifiers produced in rapid succession on the same machine are strictly ordered, which is essential for database write patterns that depend on insertion order. If the random component overflows during a single millisecond, the factory waits for the next millisecond before issuing a new identifier, preserving the monotonic guarantee without sacrificing uniqueness.

ULIDX also provides utility functions for extracting the embedded timestamp from an existing ULID string, converting between ULID and UUID representations, and validating ULID format. These utilities are fully typed, so TypeScript consumers benefit from compile-time safety across the entire API surface.

Use Cases

Database primary keys in TypeScript applications. ULIDX is an excellent choice for primary keys in relational or document databases accessed from TypeScript backends. The time-sorted nature of the identifiers reduces B-tree page splits during inserts, improving write throughput compared to random UUIDs. The monotonic factory ensures that even high-frequency inserts maintain strict ordering, which simplifies pagination queries that rely on cursor-based navigation.

Event sourcing and append-only logs. Systems that record events in strict chronological order benefit from ULIDX's monotonic generation. Each event receives an identifier that is guaranteed to sort after the previous one, eliminating the need for a separate sequence number or auto-incrementing counter. Because the timestamp is embedded in the identifier itself, consumers can extract approximate creation times directly from the event ID without joining to a metadata table.

Distributed microservices with shared data stores. In architectures where multiple services write to a common database or message broker, ULIDX identifiers provide global uniqueness without requiring a centralized ID allocation service. Each service generates identifiers independently using its own CSPRNG, and the embedded timestamp ensures that records from different services can still be merged and sorted chronologically. The 80-bit random space makes cross-service collisions effectively impossible.

Frontend-generated identifiers for offline-first applications. Progressive web applications and mobile apps that create records while offline need identifiers that will remain valid once the device reconnects and syncs with the server. ULIDX runs in any JavaScript environment, including browsers, and produces identifiers that are guaranteed to be unique and sortable. When the device eventually syncs, the server can merge offline-created records in the correct chronological order based on the embedded timestamps.

Comparison with Alternatives

ULIDX and the original ULID specification produce identical output formats, so the comparison between them is primarily about library quality rather than identifier characteristics. ULIDX offers a maintained codebase with full TypeScript declarations, a monotonic factory, and regular dependency updates. The original ulid package on npm has not seen active development for several years, and its TypeScript support is incomplete. For any new project that wants ULID-format identifiers, ULIDX is the safer choice.

Compared to UUID v7, ULIDX produces shorter strings (26 characters versus 36 characters) and uses a more compact encoding. Both formats embed a millisecond timestamp in the leading bits and fill the remainder with randomness, so their time-sorting properties are equivalent. However, UUID v7 has the advantage of being an IETF standard (RFC 9562), which means it enjoys native support in databases like PostgreSQL and libraries across every major language. If your infrastructure already uses UUID columns and you need broad interoperability without custom parsing, UUID v7 may be more practical. If you prefer shorter identifiers and are working primarily in a JavaScript or TypeScript ecosystem, ULIDX is the stronger option.

When compared to fully random identifiers like UUID v4 or Nano ID, ULIDX offers the additional benefit of chronological sorting. Random identifiers scatter inserts across database index pages, leading to write amplification and cache inefficiency at scale. ULIDX avoids this problem entirely because sequential identifiers cluster together in the index. The trade-off is that ULIDX embeds a timestamp, which reveals the approximate creation time of the record. In applications where creation-time privacy is a concern, a purely random identifier may be preferred.

Code Examples

import { ulid, monotonicFactory } from 'ulidx';
const id = ulid();

// Monotonic variant
const monotonic = monotonicFactory();
const id2 = monotonic();
console.log(id, id2);

Frequently Asked Questions

What is ulidx?

ulidx is a modern, well-maintained TypeScript library for generating ULID (Universally Unique Lexicographically Sortable Identifier) values. It provides a fast, lightweight implementation with full TypeScript type definitions, built-in monotonic support, and zero dependencies, making it a popular choice for JavaScript and TypeScript projects.

How does ulidx differ from ulid?

ulidx is a more actively maintained alternative to the original ulid package, which has not received updates in several years. ulidx offers better TypeScript support, improved performance, additional utility functions like encoding and decoding helpers, and regular updates to address security and compatibility concerns.

Does ulidx support monotonic ULIDs?

Yes, ulidx provides a dedicated monotonic ULID generation function. Monotonic ULIDs guarantee that IDs generated within the same millisecond are strictly increasing by incrementing the random component. This prevents ordering ambiguity and is essential for systems that require strict sequential ordering within the same timestamp.

Is ulidx a drop-in replacement for ulid?

For most use cases, ulidx can serve as a drop-in replacement for the original ulid package. The core API for generating and validating ULIDs is compatible. However, ulidx also offers additional functions and slightly different module exports, so you should review the import paths when migrating.

What are the advantages of ulidx?

ulidx offers several advantages over other ULID implementations: it is written in TypeScript with full type definitions, has zero runtime dependencies, supports both monotonic and non-monotonic generation, and includes utility functions for timestamp extraction and ULID validation. It is also actively maintained with regular releases.

Related Generators

© 2024 Carova Labs. All rights reserved