ULID Generator
Generate Universally Unique Lexicographically Sortable identifiers.
What is ULID?
ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier designed to solve a fundamental problem with traditional UUIDs: sortability. Created by Alizain Feerasta in 2016, ULID combines a millisecond-precision Unix timestamp with cryptographically secure randomness, all encoded in a compact 26-character string using Crockford's Base32 alphabet.
Unlike UUID v4, which is entirely random and produces IDs that scatter randomly across indexes, ULIDs embed the generation time in their first 10 characters. This means sorting ULIDs alphabetically produces chronological order � a property that is invaluable for database performance, event ordering, and log aggregation. The remaining 16 characters provide 80 bits of cryptographically secure randomness from the Web Crypto API, making collisions statistically impossible for any practical workload.
A ULID looks like this: 01ARZ3NDEKTSV4RRFFQ69G5FAV. The first 10 characters decode to a timestamp (in this case, March 21, 2024 at 14:30:45 UTC), while the final 16 characters are random. Because the timestamp occupies the most significant bits, any two ULIDs generated at different milliseconds will sort correctly, and ULIDs generated within the same millisecond will sort by their random suffix.
ULID vs UUID v4
| Feature | ULID | UUID v4 |
|---|---|---|
| Bit Size | 128-bit | 128-bit |
| String Length | 26 characters | 36 characters (with hyphens) |
| Encoding | Crockford's Base32 | Hexadecimal |
| Timestamp Component | Yes (48-bit millisecond) | No |
| Lexicographically Sortable | Yes | No |
| Randomness Bits | 80 bits | 122 bits |
| URL-Safe | Yes (no special characters) | No (contains hyphens) |
| Case Sensitivity | Case-insensitive | Case-insensitive |
| RFC Standard | No (community spec) | Yes (RFC 4122) |
Choose ULID when you need time-ordered identifiers for database indexes, event logs, or sorted lists. Choose UUID v4 when you need maximum randomness, standards compliance, or have no sorting requirements. Both work well as distributed system identifiers � the decision comes down to whether you need chronological sort order.
When to Use ULID
Database Primary Keys
ULIDs excel as primary keys in PostgreSQL, MySQL, and MongoDB. Their time-ordered nature keeps B-tree indexes efficient, reducing page splits and write amplification compared to random UUID v4 keys. You can also extract the timestamp from any ID to determine when a record was created without a separate created_at column.
Event Sourcing
Event-driven architectures require events to be processed in order. ULIDs naturally sort by time, making them ideal for event IDs in Kafka topics, event stores, and CQRS systems. Consumers can sort events by ID alone and get correct chronological processing order without additional timestamp fields.
Distributed Systems
In microservices and distributed databases, ULIDs can be generated independently on any node without coordination. Unlike auto-increment IDs, they do not require a central authority. Unlike UUID v4, they maintain temporal order across nodes, enabling consistent merge operations in systems like CockroachDB and YugabyteDB.
Log Aggregation
When aggregating logs from multiple services, ULIDs let you merge and sort log entries from different sources into a single chronological timeline. Since each log entry's ID encodes the exact millisecond it was created, you can reconstruct the precise sequence of events across your entire infrastructure without relying on synchronized clocks.
Why Sortability Matters
The single most important advantage of ULID over UUID v4 is lexicographic sortability. When you sort ULID strings alphabetically, the result is chronological order. This property has profound implications for database performance, debugging, and data organization.
B-Tree Index Efficiency
Random UUIDs cause constant page splits in B-tree indexes because new inserts land at random positions across the index. ULIDs insert at the current "tail" of the index, producing sequential writes that database engines handle efficiently. In benchmarks, ULID primary keys can improve write throughput by 2-3x compared to UUID v4 on PostgreSQL and MySQL.
Natural Time-Range Queries
Since ULIDs encode time, you can query all records created in a specific time window using simple string comparisons: SELECT * FROM events WHERE id >= '01H0000000' AND id < '01H010000'. No JOIN on a timestamp column required. This pattern is especially powerful in event sourcing and audit log systems where time-range queries are frequent.
Consistent Merge Order
When merging data from multiple databases or replicas, ULIDs guarantee that records sort by creation time. This eliminates the need for additional coordination or timestamp columns during merge operations. Systems like Kafka, database replication, and distributed caches all benefit from this property when reconciling data across nodes.
Common ULID Mistakes
Using ULIDs as Authentication Tokens
ULIDs are identifiers, not secrets. They are frequently logged in server access logs, browser developer tools, HTTP headers, and analytics pipelines. The timestamp portion also leaks generation time. Never use a ULID as an API key, password reset token, or session credential. Generate dedicated cryptographic tokens with SHA-256 hashing or a dedicated secret generator instead.
Assuming ULIDs Are Globally Unique Across All Time
ULIDs share the same millisecond timestamp for all IDs generated within that millisecond. If two nodes generate ULIDs at the same millisecond, the random suffix (80 bits) must prevent collisions. While 80 bits provides roughly 1.2 � 10^24 possible values per millisecond, extremely high-throughput systems generating millions of IDs per millisecond should monitor for theoretical collision risk. Consider UUID v7 for higher randomness within the same time-ordered structure.
Storing ULIDs in Non-Optimized Column Types
Storing ULIDs as 26-character VARCHAR strings works but wastes storage compared to binary representations. PostgreSQL supports native ULID storage via extensions, and MySQL can use BINARY(16) for compact storage. However, the Base32 encoding of ULIDs makes string storage more efficient than UUID string storage (26 bytes vs 36 bytes), so the overhead is less severe than with UUIDs.
Relying on ULID Uniqueness Across Clock Skew
ULIDs derive their timestamp from the system clock. If a server's clock is set backward, it may generate ULIDs with timestamps earlier than previously generated IDs, breaking sort order guarantees. This is especially dangerous in distributed systems where clock skew between nodes can cause ULIDs from Node A to sort before ULIDs from Node B even though A generated them later. Use NTP synchronization and consider logical clocks for critical ordering guarantees.
Ignoring ULID Monotonicity Within a Millisecond
Some ULID implementations guarantee monotonicity within a single millisecond by incrementing a counter instead of generating fresh randomness. This is not part of the ULID specification � different libraries handle this differently. If your application requires strict monotonic ordering within a millisecond, verify your library's behavior or implement a custom monotonic ULID generator. Non-monotonic ULIDs within the same millisecond will sort by their random component, which is effectively arbitrary.
Frequently Asked Questions
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier that combines a millisecond-precision timestamp with cryptographically secure randomness. Unlike UUID v4 which is entirely random, ULID encodes the timestamp in its first 10 characters, making it lexicographically sortable. ULIDs are 26 characters long using Crockford's Base32 encoding, compared to UUID's 36 characters with hyphens.
Yes. ULIDs are explicitly designed for lexicographic sortability. Because the timestamp occupies the first 10 characters and is encoded in Base32, sorting ULIDs alphabetically produces chronological order. This makes them ideal for database indexes, event logs, and any system where insertion order matters.
No. ULIDs are identifiers, not secrets. While they contain 128 bits of randomness, the timestamp portion leaks generation time and they are often logged in access logs, URLs, and analytics pipelines. Never use ULIDs as authentication tokens, API keys, or password reset links. Use dedicated cryptographic token generators for security-sensitive operations.
A ULID has 128 bits total: 48 bits for the millisecond timestamp and 80 bits for randomness. The collision probability for the random component is approximately 1 in 2^80, or roughly 1.2 � 10^24. This is lower than UUID v4's randomness (122 bits), but still sufficient for virtually all practical applications. For extremely high-volume systems generating millions of IDs per millisecond, consider the practical ceiling of 2^80 random values per timestamp.
It depends on your workload. ULIDs are excellent for write-heavy databases because their time-ordered nature reduces B-tree index fragmentation compared to random UUID v4 values. They also let you query records by time range using the ID alone. However, if you need maximum randomness with no timestamp leakage, UUID v4 remains the better choice. For the best of both worlds, consider UUID v7 which combines time-ordering with the UUID standard format.
The first 10 characters of a ULID encode a 48-bit millisecond timestamp using Crockford's Base32 alphabet (0-9, A-H, J-K, M-N, P-T, V-W, X-Y, Z). To decode, convert each character to its Base32 value and reconstruct the 48-bit integer, which represents milliseconds since the Unix epoch (January 1, 1970). This ULID generator tool displays the decoded timestamp automatically below each generated ID.
ULID has official and community libraries for virtually every major language. JavaScript has the 'ulid' npm package, Go has 'github.com/oklog/ulid', Python has 'python-ulid', Rust has 'ulid-rs', and Java has 'ulid-generator'. Most modern database ORMs also include native ULID support, including Prisma, Drizzle, and SQLAlchemy.
Related Resources
UUID Generator
Generate RFC 4122 compliant UUIDs in v4 (random) format. The industry standard for globally unique identifiers.
Compact IDsNanoID Generator
Create compact, URL-friendly identifiers with configurable length and alphabet for short-link and invitation systems.
UUID UtilitiesUUID Tools
Parse, validate, and convert UUIDs between different formats. Decode version information and inspect UUID structure.
Cryptographic HashingSHA-256 Generator
Generate SHA-256 hashes for data integrity verification, digital signatures, and password storage applications.
Introduction
ULID solves a problem UUIDs and NanoIDs can't: sortable identifiers. When you insert records into a database, time-ordered IDs give you natural clustering — new records are always appended, not scattered randomly across B-tree pages. ULID encodes a 48-bit millisecond timestamp in the first 80 bits, followed by 48 bits of cryptographically random data. The result is a 26-character Crockford Base32 string that sorts lexicographically in creation order. It's the identifier that makes your database indexes fast, your logs chronological, and your APIs predictable — all without sacrificing the randomness that prevents enumeration.
What This Tool Does
Why It Matters
Random identifiers like UUIDv4 scatter inserts across B-tree index pages, causing page splits, cache misses, and degraded write performance at scale. ULID's time-ordered prefix means sequential inserts target the same index leaf page, reducing I/O by 40-60% in write-heavy workloads. For time-series data, ULID enables natural range queries without a separate timestamp column. The 26-character compact format fits in single-line displays, JSON payloads, and URL segments without the hyphens and padding that bloat UUIDs. ULID is the standard choice for systems that need both uniqueness and chronological ordering.
How It Works
Step-by-Step Examples
Click Generate to produce a 26-character Crockford Base32 string
Observe the first 10 characters encode the current timestamp (milliseconds since Unix epoch)
The remaining 16 characters are cryptographically random
Sort a batch of ULIDs and confirm they appear in chronological order
01ARZ3NDEKTSV4RRFFQ68GABC8 — timestamp: 01ARZ3NDEK (milliseconds since epoch), random: TS4RRFFQ68GABC8Click Generate 5 times with short delays between clicks
Record each ULID and its generation timestamp
Sort the ULIDs alphabetically (ascending)
Confirm the alphabetical sort order matches the chronological generation order
01ARZ3NDEK → 01ARZ3NDEL → 01ARZ3NDEM → 01ARZ3NDEN → 01ARZ3NDEO — alphabetical sort = chronological sortCode Examples
const CROCKFORD = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
function encodeTime(time, length) {
let str = '';
for (let i = 0; i < length; i++) {
str = CROCKFORD[time % 32] + str;
time = Math.floor(time / 32);
}
return str;
}
function encodeRandom(length) {
const bytes = new Uint8Array(length);
crypto.getRandomValues(bytes);
let str = '';
for (let i = 0; i < length; i++) {
str += CROCKFORD[bytes[i] % 32];
}
return str;
}
function generateULID() {
const time = Date.now();
const timestamp = encodeTime(time, 10);
const random = encodeRandom(16);
return timestamp + random;
}
// Generate ULIDs — they sort chronologically
const ids = Array.from({ length: 5 }, generateULID);
ids.sort(); // Lexicographic sort = chronological sort
console.log(ids);function extractULIDTimestamp(ulid) {
const CROCKFORD_MAP = {};
'0123456789ABCDEFGHJKMNPQRSTVWXYZ'.split('').forEach((c, i) => {
CROCKFORD_MAP[c] = i;
});
let time = 0;
for (let i = 0; i < 10; i++) {
time = time * 32 + CROCKFORD_MAP[ulid[i]];
}
return {
ulid,
timestamp: time,
date: new Date(time).toISOString(),
timeSinceEpoch: (time / 1000).toFixed(1) + ' seconds since Unix epoch'
};
}
// Usage
const result = extractULIDTimestamp('01ARZ3NDEKTS4RRFFQ68GABC8');
console.log(result.date); // ISO timestamp of generation
console.log(result.timeSinceEpoch); // "58451.2 seconds since Unix epoch"ULID Component Breakdown
| Component | Bits | Crockford Chars | Content | Example |
|---|---|---|---|---|
| Timestamp | 48 | 10 | Milliseconds since Unix epoch | 01ARZ3NDEK |
| Random | 48 | 16 | Cryptographically random bits | TS4RRFFQ68GABC8 |
| Total | 96 | 26 | Crockford Base32 encoded | 01ARZ3NDEKTS4RRFFQ68GABC8 |
ULID vs Other Sortable IDs
| ID Type | Length | Sort Order | Entropy | Resolution |
|---|---|---|---|---|
| ULID | 26 chars | Lexicographic | 128 bits total (80 timestamp + 48 random) | 1 millisecond |
| UUIDv7 | 36 chars | Lexicographic | 122 bits random portion | 1 nanosecond |
| Snowflake | ~20 chars | Numeric | 64 bits | 1 millisecond |
| ObjectID (Mongo) | 24 chars | Lexicographic | 80 bits total | 1 second |
| KSUID | 27 chars | Lexicographic | 128 bits | 1 second |
Benefits
- Lexicographically sortable — alphabetical sort of ULIDs equals chronological sort, enabling natural database ordering.
- 48-bit millisecond timestamp provides 136 years of unique time representation from the Unix epoch.
- 26-character Crockford Base32 format is URL-safe, case-insensitive, and contains no special characters.
- Monotonic randomness within the same millisecond — the random component increments if generated multiple times per tick.
Use Cases
Database primary keys in write-heavy systems where time-ordered inserts reduce B-tree page splits and improve cache locality.
Time-series data ingestion where ULID enables range queries without a separate timestamp column.
Event sourcing and audit logs where chronological ordering of events must be embedded in the identifier itself.
Distributed systems requiring globally unique, time-sortable identifiers without coordination between nodes.
Common Mistakes to Avoid
Using ULIDs as authentication tokens — the timestamp prefix is predictable and leaks creation time, reducing effective entropy.
Assuming ULIDs are globally unique across time — two ULIDs generated in the same millisecond on different machines could collide if the random bits match.
Sorting ULIDs lexicographically in non-Crockford-compatible tools — uppercase/lowercase handling varies by implementation.
Truncating ULIDs to save space — the timestamp prefix is critical for sort order; removing it destroys time-ordered guarantees.
Security Implications
ULID provides 48 bits of cryptographically secure randomness in its random component, which is sufficient for public identifiers but less than UUIDv4's 122 bits. The timestamp prefix is not secret — anyone who knows the generation time can narrow the search space from 2^48 to a much smaller range. ULID is designed for uniqueness and sortability, not for security. Never use ULIDs as authentication tokens, session IDs, or any credential where predictability of the timestamp component would create a vulnerability.
Security Information
Frequently Asked Questions
References & Further Reading
What is a ULID?
ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier that combines a timestamp with random data. Unlike UUID v4, which is purely random, ULIDs embed a Unix timestamp in the first 48 bits, making them lexicographically sortable. This means ULIDs generated later will always sort after earlier ones, which is incredibly useful for database indexing and log ordering.
ULIDs are 26 characters long and use Crockford's Base32 encoding (0-9, A-H, J-K, M-N, P-T, V-Z), making them URL-safe, case-insensitive, and easy to read. They provide 128 bits of uniqueness, comparable to UUID v4, while adding the significant advantage of time-based sorting.
How ULID Generation Works
A ULID consists of two parts: a 48-bit timestamp and 80 bits of cryptographically secure random data. The timestamp uses millisecond precision from the Unix epoch, providing approximately 8,900 years of unique timestamps. The random component ensures uniqueness within the same millisecond.
Lexicographic Sorting: Because the timestamp occupies the most significant bits, ULIDs sort naturally in lexicographic order. This makes them ideal for database primary keys where insertion order matters, and for log entries that need to be processed in chronological order.
Crockford's Base32: The encoding uses 32 characters that are URL-safe and visually distinct. The characters I, L, O, U are excluded to avoid confusion with 1, 1, 0, and V. This makes ULIDs safe for URLs, filenames, and other contexts where special characters cause problems.
Where ULIDs Excel
Database Primary Keys: ULIDs provide unique, time-sortable identifiers for database records. They avoid the sequential ID problem (which leaks business information) while maintaining sort order.
Event Sourcing: In event-driven architectures, ULIDs ensure events are processed in the correct order while maintaining uniqueness across distributed systems.
Log Aggregation: When combining logs from multiple sources, ULIDs provide a natural sort order without requiring separate timestamp fields.
File Naming: ULIDs in filenames ensure files sort in creation order, making directory listings and backups easier to manage.
ULID Implementation Mistakes
Using ULIDs for Security Tokens: ULIDs embed timestamps, which leak information about when they were created. For security tokens, API keys, or session identifiers, use purely random identifiers like UUID v4 or NanoID.
Not Using Cryptographic Randomness: The random component must use a CSPRNG. Using Math.random() produces predictable ULIDs that can be forged. Always use crypto.getRandomValues().
Ignoring Monotonicity: Within the same millisecond, ULIDs should be monotonically increasing. Our generator handles this automatically, but custom implementations must ensure proper monotonic ordering.
Assuming Global Uniqueness: While ULIDs provide 128 bits of randomness, they are not globally unique by specification. For guaranteed uniqueness across distributed systems, combine ULIDs with coordination mechanisms or use UUID v1.
Related Identifier Tools
Explore these unique identifier generation tools:
- UUID Generator — Generate standard UUID v4 identifiers for broader compatibility.
- NanoID Generator — Create compact, URL-friendly identifiers with customizable length.
- UUID Tools — Multi-format identifier generation including UUID, ULID, and NanoID.
- Random Bytes Generator — Generate cryptographically secure random bytes.
- Secret Token Generator — Generate secure tokens for authentication and API keys.