ULID Generator — TypeScript source
Generate Universally Unique Lexicographically Sortable Identifiers (ULID) - 26-character Crockford-base32 strings that sort by millisecond timestamp. Paste any ULID to decode its timestamp and randomness. Runs entirely in your browser.
This is the TypeScript implementation — the same logic the interactive tool runs, in a shareable, citable form.
// ULID generator backed by the `ulid` package. Injectable time + RNG for
// deterministic tests. The unit-test surface for the ULID Generator tool.
import { ulid, decodeTime, isValid } from 'ulid';
export interface UlidOptions {
timestamp?: number; // ms since epoch; defaults to now
rng?: () => number; // [0, 1)
}
/** Generate a ULID, optionally pinned to a timestamp and/or custom RNG. */
export function generateUlid(opts: UlidOptions = {}): string {
return opts.rng ? ulid(opts.timestamp, opts.rng) : ulid(opts.timestamp);
}
/** Decode the embedded timestamp (ms since epoch) from a ULID. */
export function decodeUlidTime(id: string): number {
return decodeTime(id);
}
export interface UlidInfo {
valid: boolean;
/** Why the input is not a valid ULID (present only when invalid). */
error?: string;
/** First 10 chars — the Crockford-base32 encoded timestamp. */
timePart?: string;
/** Last 16 chars — the random part. */
randomness?: string;
/** Decoded timestamp, ms since epoch (48-bit ceiling: 281474976710655). */
timestamp?: number;
/** Timestamp as ISO-8601 UTC. */
iso?: string;
}
/** Inspect a pasted ULID: validate and break out time part, randomness, timestamp. */
export function inspectUlid(input: string): UlidInfo {
const id = input.trim().toUpperCase();
if (id.length !== 26) {
return { valid: false, error: `Length must be 26 characters, got ${id.length}` };
}
// The package's own isValid covers the Crockford charset (its decode table
// is the alphabet's single source of truth — no third regex copy here).
if (!isValid(id)) {
return { valid: false, error: 'Invalid character — ULIDs use Crockford base32 (no I, L, O, U)' };
}
try {
const timestamp = decodeTime(id);
return {
valid: true,
timePart: id.slice(0, 10),
randomness: id.slice(10),
timestamp,
iso: new Date(timestamp).toISOString(),
};
} catch {
return { valid: false, error: 'Time part overflows the 48-bit ULID timestamp ceiling' };
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →