Generate a ULID string or write the bytes into a buffer.ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier with millisecond timestamp precision and 80 bits of randomness. ULIDs are URL-safe, use Crockford’s Base32 encoding, and sort lexicographically by creation time.
const id = ulid()const ts = ulid.timestamp(id)console.log(new Date(ts))// => Date object representing when the ULID was createdconsole.log(Date.now() - ts)// => Milliseconds elapsed since ULID creation
Note: Only the first 10 characters of the ULID encode the timestamp.
ULID maintains module-level state to ensure IDs are monotonically increasing even when generated within the same millisecond:
// All called within the same millisecondconst id1 = ulid() // random portion = new random valueconst id2 = ulid() // random portion = incrementedconst id3 = ulid() // random portion = incremented again// Guaranteed to be in lexicographic orderconsole.log(id1 < id2 && id2 < id3) // true
Important: This module-level state persists across calls:
In serverless/edge functions with warm starts, state persists between invocations
For isolated state, pass explicit msecs and random via options
Tests should mock Date.now() or provide explicit options for deterministic behavior
Cloudflare Workers note: Cloudflare Workers “freeze” time during request handling to prevent side-channel attacks. This means all ULIDs generated within a single request will have the same timestamp, and monotonic ordering will rely entirely on incrementing the random portion.
export type UlidOptions = { /** * 16 bytes of random data to use for ULID generation. * Only the first 10 bytes are used. */ random?: Uint8Array /** * Timestamp in milliseconds since Unix epoch. * Defaults to Date.now(). */ msecs?: number}export type Ulid = { (): string <TBuf extends Uint8Array = Uint8Array>(options: UlidOptions | undefined, buf: TBuf, offset?: number): TBuf (options?: UlidOptions, buf?: undefined, offset?: number): string toBytes(id: string): Uint8Array fromBytes(bytes: Uint8Array): string timestamp(id: string): number isValid(id: unknown): id is string /** The nil ULID (all zeros) */ NIL: string /** The max ULID (maximum valid value) */ MAX: string}