🆔 Generates a ULID: a 128-bit, lexicographically sortable identifier.

The first 48 bits are the timestamp in milliseconds and the remaining 80 are random, encoded together as 26 characters of Crockford's Base32. Because the time leads and the encoding preserves order, sorting the strings sorts by creation time — no separate column, and no parsing to compare two of them.

Syntax

TypeScript
import { ulid } from '@opentf/std';
ulid(seedTime?: number): string;

Parameters

NameTypeDefaultDescription
seedTimenumberDate.now()The timestamp to encode, in milliseconds.

Returns

A 26-character ULID. Throws a RangeError if seedTime is not an integer within the 48-bit range — which runs out in the year 10889.

Warning

Ordering holds between milliseconds, not within one. Two ULIDs made in the same millisecond differ only in their random half, so their relative order is arbitrary. That is what the specification defines for this function; it recommends a monotonic factory where same-millisecond order has to be stable.

Examples

TypeScript
ulid() //=> '01ARZ3NDEKTSV4RRFFQ69G5FAV'

Sorting the strings sorts by creation time:

TypeScript
const ids = [ulid(), ulid(), ulid()];

ids.sort(); // already in creation order

A fixed time gives a fixed 10-character prefix, which makes it testable and lets you build a range query over an interval:

TypeScript
ulid(1469918176385).slice(0, 10) //=> '01ARYZ6S41'

ULID or uuidv7?

Both put the time first so they sort. They differ in shape:

uliduuidv7
Length26 characters36 characters
AlphabetCrockford's Base32, no I L O Uhex with hyphens
Fits a UUID columnnoyes
Random bits8074

A ULID is not a UUID and will not pass a UUID column or validator. Reach for uuidv7 when the shape has to be a UUID.

Last updated on
Edit this page