@digicroz/ulid
v1.0.0
Published
TypeScript ULID library with monotonic generation, binary conversion, and validation - Universally Unique Lexicographically Sortable Identifiers for JavaScript and TypeScript projects
Downloads
96
Maintainers
Readme
@digicroz/ulid
TypeScript ULID library with monotonic generation and binary conversion - Universally Unique Lexicographically Sortable Identifiers for JavaScript and TypeScript projects.
A TypeScript library for generating and manipulating ULIDs (Universally Unique Lexicographically Sortable Identifiers).
🌐 Environment Compatibility
This library is designed to work across multiple JavaScript environments:
- ✅ Node.js - Server-side applications
- ✅ Browser - Client-side web applications
- ✅ Web Workers - Background processing
- ✅ React Native - Mobile applications
What is ULID?
ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier that is:
- Sortable - Lexicographically sortable by time
- Compact - 26 characters (vs 36 for UUID)
- URL-safe - Uses Crockford's Base32 alphabet
- Case-insensitive - No ambiguous characters
- Monotonic - Guaranteed ordering within the same millisecond
- Time-based - Encodes a timestamp in the first 48 bits
Features
- 🚀 TypeScript Support - Full TypeScript support with type definitions
- 📦 Tree Shakable - Import only what you need
- 🔧 Monotonic Generation - Ensures IDs are always increasing
- 💾 Binary Conversion - Lossless conversion between string and binary formats
- ✅ Validation - Built-in ULID format validation
- ⏰ Time Decoding - Extract timestamps from ULIDs
- 🌐 Cross-Platform - Works in Node.js, browsers, and web workers
- 💡 Excellent IDE Support - Full auto-completion and IntelliSense support
Installation
npm install @digicroz/ulidAlternative package managers:
# Yarn
yarn add @digicroz/ulid
# pnpm
pnpm add @digicroz/ulid
# Bun
bun add @digicroz/ulidQuick Start
import { generateUlid, isValidUlid, decodeTimeFromUlid } from "@digicroz/ulid";
// Generate a new ULID
const id = generateUlid();
console.log(id); // "01JCQX5YQHJ8Z9KQXH5YQHJ8Z0"
// Validate ULID format
const isValid = isValidUlid(id);
console.log(isValid); // true
// Decode timestamp from ULID
const timestamp = decodeTimeFromUlid(id);
console.log(new Date(timestamp)); // Current date/timeAPI Reference
Core Functions
generateUlid(seedTime?: number): string
Generates a new ULID with monotonic guarantees.
import { generateUlid } from "@digicroz/ulid";
// Generate with current time
const id1 = generateUlid();
// Generate with specific timestamp
const id2 = generateUlid(Date.now());Features:
- Monotonic mode ensures IDs are always increasing
- Last character is always '0' for perfect 128-bit binary conversion
- Handles clock drift gracefully
isValidUlid(id: string): boolean
Validates if a string is a valid ULID format.
import { isValidUlid } from "@digicroz/ulid";
isValidUlid("01JCQX5YQHJ8Z9KQXH5YQHJ8Z0"); // true
isValidUlid("invalid"); // false
isValidUlid("01JCQX5YQHJ8Z9KQXH5YQHJ8ZI"); // false (invalid character 'I')Validation checks:
- Exactly 26 characters
- All characters are valid Crockford Base32 (0-9, A-Z excluding I, L, O, U)
- Case-insensitive
decodeTimeFromUlid(id: string): number
Extracts the timestamp from a ULID.
import { decodeTimeFromUlid } from "@digicroz/ulid";
const id = "01JCQX5YQHJ8Z9KQXH5YQHJ8Z0";
const timestamp = decodeTimeFromUlid(id);
console.log(new Date(timestamp)); // Date when the ULID was created
// Throws error if invalid ULID
try {
decodeTimeFromUlid("invalid");
} catch (error) {
console.error("Invalid ULID format");
}getUlidAge(id: string): number
Returns the age of a ULID in milliseconds.
import { getUlidAge } from "@digicroz/ulid";
const id = generateUlid();
// ... some time passes ...
const age = getUlidAge(id);
console.log(`ULID is ${age}ms old`);parseUlid(id: string): object
Parses a ULID and extracts all its components.
import { parseUlid } from "@digicroz/ulid";
const id = "01JCQX5YQHJ8Z9KQXH5YQHJ8Z0";
const parsed = parseUlid(id);
console.log(parsed);
// {
// timestamp: 1699891200000, // milliseconds since epoch
// timestampSeconds: 1699891200, // seconds since epoch
// age: 1234 // milliseconds since creation
// }Binary Conversion Functions
ulidToBinary(id: string): Uint8Array
Converts a ULID string to 16-byte binary format for efficient storage.
import { ulidToBinary } from "@digicroz/ulid";
const id = "01JCQX5YQHJ8Z9KQXH5YQHJ8Z0";
const binary = ulidToBinary(id);
console.log(binary); // Uint8Array(16) [...]
console.log(binary.length); // 16 bytes (128 bits)Benefits:
- Lossless conversion (100% reversible)
- Saves space in databases (16 bytes vs 26 characters)
- Perfect for binary storage formats
binaryToUlid(bytes: Uint8Array | Buffer): string
Converts 16-byte binary format back to ULID string.
import { binaryToUlid, ulidToBinary } from "@digicroz/ulid";
const id = "01JCQX5YQHJ8Z9KQXH5YQHJ8Z0";
const binary = ulidToBinary(id);
const restored = binaryToUlid(binary);
console.log(id === restored); // true (lossless conversion)Features:
- Works with both
Uint8Arrayand Node.jsBuffer - Maintains consistency with generated ULIDs (last char is '0')
Usage Examples
Database Storage
Store ULIDs efficiently in binary format:
import { generateUlid, ulidToBinary, binaryToUlid } from "@digicroz/ulid";
// Generate ULID
const userId = generateUlid();
// Store in database as binary (saves space)
const binaryId = ulidToBinary(userId);
await db.users.insert({ id: binaryId, name: "John" });
// Retrieve and convert back
const user = await db.users.findOne({ id: binaryId });
const readableId = binaryToUlid(user.id);
console.log(readableId); // Original ULID stringSorting by Creation Time
ULIDs are naturally sortable by creation time:
import { generateUlid } from "@digicroz/ulid";
const ids = [];
ids.push(generateUlid());
await sleep(10);
ids.push(generateUlid());
await sleep(10);
ids.push(generateUlid());
// Sort naturally
ids.sort();
// IDs are now in chronological order!URL-safe Identifiers
Use ULIDs in URLs without encoding:
import { generateUlid } from "@digicroz/ulid";
const articleId = generateUlid();
const url = `https://example.com/articles/${articleId}`;
// No URL encoding needed!Distributed Systems
ULIDs work great in distributed systems:
import { generateUlid } from "@digicroz/ulid";
// Each server can generate unique IDs independently
// Server 1
const serverId1 = generateUlid();
// Server 2 (at the same time)
const serverId2 = generateUlid();
// IDs are guaranteed unique and sortable across serversTypeScript Configuration
For optimal compatibility, ensure your tsconfig.json uses modern module resolution:
{
"compilerOptions": {
"moduleResolution": "bundler", // or "node16"/"nodenext"
"module": "ESNext",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true
}
}ULID Specification
This library implements the ULID specification:
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
Timestamp Randomness
48bits 80bits- Timestamp: 48-bit integer (millisecond precision)
- Randomness: 80-bit random number
- Encoding: Crockford's Base32 (case-insensitive)
- Length: 26 characters
- Sortable: Lexicographically by time
Character Set
Uses Crockford's Base32 for better readability:
0123456789ABCDEFGHJKMNPQRSTVWXYZExcluded characters: I, L, O, U (to avoid confusion)
Comparison with UUID
| Feature | ULID | UUID v4 | | ------------------------ | ---------------- | ---------------------------- | | Length | 26 characters | 36 characters (with hyphens) | | Sortable | ✅ Yes (by time) | ❌ No | | Monotonic | ✅ Yes | ❌ No | | URL-safe | ✅ Yes | ⚠️ Needs encoding | | Case-sensitive | ❌ No | ✅ Yes | | Timestamp | ✅ Embedded | ❌ No | | Collision Resistance | ✅ High | ✅ High | | Binary Size | 128 bits | 128 bits |
Performance
- Generation: ~100,000 IDs per second (monotonic mode)
- Validation: ~1,000,000 validations per second
- Binary Conversion: ~500,000 conversions per second
Browser Support
Works in all modern browsers:
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- React Native
- Web Workers
Node.js Support
Requires Node.js 16.0.0 or higher.
Development
# Install dependencies
npm install
# Build the project
npm run build
# Watch mode for development
npm run dev
# Clean build artifacts
npm run cleanLicense
MIT © Adarsh Hatkar
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Related Projects
Support
For issues and feature requests, please use the GitHub issue tracker.
