ULID (Sortable Unique ID) Generator
Generate ULIDs (Universally Unique Lexicographically Sortable Identifiers). Bulk generate up to 100 with embedded timestamps.
ULIDs (Universally Unique Lexicographically Sortable Identifiers) are an alternative to UUIDs that sort in chronological order. This generator creates ULIDs in your browser using the Web Crypto API, with support for bulk generation of up to 100 IDs and automatic timestamp decoding for each one. No data leaves your device.
About ULID (Sortable Unique ID) Generator
How ULIDs Work
A ULID is a 128-bit identifier encoded as 26 characters in Crockford Base32. The first 10 characters encode a 48-bit millisecond Unix timestamp, and the remaining 16 characters encode 80 bits of cryptographic randomness. Because the timestamp occupies the most significant bits, any two ULIDs generated at different times will sort in chronological order when compared as plain strings.
| Component | Characters | Bits | Purpose |
|---|---|---|---|
| Timestamp | First 10 | 48 | Millisecond Unix timestamp (sortable, extractable) |
| Randomness | Last 16 | 80 | Cryptographic random data (uniqueness within the same millisecond) |
| Total | 26 | 128 | Globally unique, chronologically sortable identifier |
Worked example: Take the ULID 01ARZ3NDEKTSV4RRFFQ69G5FAV. The first 10 characters (01ARZ3NDEK) are decoded by treating each character as a Crockford Base32 digit and converting to a base-10 number. Each character position represents a power of 32, so the leftmost character is multiplied by 32^9, the next by 32^8, and so on. The result is a Unix timestamp in milliseconds. The remaining 16 characters (TSV4RRFFQ69G5FAV) are random bytes that ensure uniqueness even if two IDs are created in the same millisecond on different machines.
ULID vs UUID - Which Should You Use?
UUID v4 has been the default choice for unique IDs since RFC 4122 was published in 2005, but its random ordering creates real problems at scale. RFC 9562, published in May 2024, introduced UUID v7 as a time-ordered alternative within the UUID family. ULIDs predate UUID v7 and solve the same core problem - sortable unique IDs - but with a different encoding. The npm ulid package alone sees over 5 million weekly downloads as of early 2026, showing strong adoption in the JavaScript ecosystem.
| Property | ULID | UUID v4 | UUID v7 |
|---|---|---|---|
| Length | 26 characters | 36 characters (with hyphens) | 36 characters (with hyphens) |
| Encoding | Crockford Base32 | Hexadecimal with hyphens | Hexadecimal with hyphens |
| Sortable by time | Yes - lexicographic sort = chronological | No - random order | Yes - same principle as ULID |
| Timestamp extractable | Yes - millisecond precision | No | Yes - millisecond precision |
| Random bits | 80 | 122 | 62 |
| Total bits | 128 | 128 | 128 |
| Case sensitive | No | No | No |
| Standard | Community spec (ulid/spec on GitHub) | RFC 9562 | RFC 9562 |
| Database index performance | Excellent (sequential inserts) | Poor (random inserts fragment B-tree) | Excellent (sequential inserts) |
The practical choice often comes down to ecosystem. If your stack already uses UUID columns and you want to stay within that format, UUID v7 slots in directly. If you want shorter, more readable IDs and don't need strict UUID compatibility, ULIDs are the better fit. For standard UUIDs, see the UUID generator.
Why Sortability Matters for Databases
When random UUIDs (v4) are used as primary keys, each new insert goes to a random position in the B-tree index. This causes page splits, fragmentation, and slower write performance as the table grows. Benchmarks consistently show that time-ordered IDs like ULIDs and UUID v7 reduce write amplification and improve insert throughput compared to UUID v4, particularly on tables with millions of rows.
ULIDs are generated in chronological order, so new records always append to the end of the index - similar to auto-incrementing integers but without requiring a central counter or database round-trip. This also means you can query by time range using the ID column alone, since filtering by a ULID prefix is equivalent to filtering by timestamp.
| ID Type | Insert Pattern | Index Performance | Query by Time Range |
|---|---|---|---|
| Auto-increment integer | Sequential | Excellent | Requires a separate timestamp column |
| UUID v4 | Random | Poor (B-tree fragmentation) | Requires a separate timestamp column |
| ULID | Sequential (time-based) | Excellent | Built in - filter or sort by ID prefix |
| UUID v7 | Sequential (time-based) | Excellent | Built in - timestamp in most significant bits |
Monotonicity and Collision Resistance
Within the same millisecond, ULIDs are not guaranteed to sort in creation order unless the implementation uses monotonic mode. In monotonic mode, the 80-bit random component is incremented by 1 for each ULID generated within the same millisecond tick. This preserves strict ordering even under high throughput. If the random component overflows (more than 2^80 increments in a single millisecond - an astronomically unlikely scenario), the generator returns an error rather than producing an out-of-order ID.
The 80 bits of randomness give each millisecond a collision space of roughly 1.2 x 10^24 possible values. For context, generating 1 billion ULIDs per second within a single millisecond would still leave the probability of a collision effectively zero. Across different milliseconds, collisions are impossible since the timestamp portion differs.
The 48-bit timestamp supports dates up to the year 10889 AD (2^48 - 1 milliseconds from the Unix epoch), so the format will not run out of timestamp space for roughly 8,800 years.
Crockford Base32 Encoding
ULIDs use Crockford Base32, an encoding designed by Douglas Crockford specifically for human-friendly data representation. It encodes 5 bits per character, which is why 128 bits fit neatly into 26 characters (128 / 5 = 25.6, rounded up to 26).
| Feature | Details |
|---|---|
| Character set | 0123456789ABCDEFGHJKMNPQRSTVWXYZ (32 characters) |
| Excluded: I, L | Too similar to the digit 1 in many fonts |
| Excluded: O | Too similar to the digit 0 |
| Excluded: U | Avoids accidentally spelling offensive words |
| Case insensitive | Lowercase and uppercase decode identically |
| Maximum value | 7ZZZZZZZZZZZZZZZZZZZZZZZZZ (the largest valid ULID) |
The case insensitivity is a practical advantage over hex-based UUIDs. A ULID pasted as 01arz3ndek... or 01ARZ3NDEK... decodes to the same value, which avoids bugs caused by inconsistent casing in URLs, filenames, or database queries.
Common Use Cases
| Use Case | Why ULID Works Well |
|---|---|
| Database primary keys | Sequential inserts, no coordination needed, timestamp built in |
| Event sourcing | Events naturally sort by creation time without a separate sequence number |
| Distributed systems | Generated independently on any node with no central counter |
| Log correlation IDs | Sorting by ID gives you chronological order for debugging |
| File and object naming | Files sort chronologically in directory listings |
| API idempotency keys | Unique per request, sortable for audit trails |
| Microservice request tracing | Trace IDs embed creation time, making span ordering trivial |
Storing ULIDs in Your Database
ULIDs are the same 128-bit size as UUIDs, so they fit into UUID-type columns with a binary conversion. In PostgreSQL, you can store a ULID as a uuid type by converting the 128 bits to the standard UUID binary format. Many libraries (such as ulidx for JavaScript and ulid for Go) include built-in conversion functions. Alternatively, storing ULIDs as a fixed-length CHAR(26) column works well and keeps the value human-readable in query results. For MySQL and MariaDB, a BINARY(16) column is the most space-efficient option.
| Database | Recommended Column Type | Size on Disk | Notes |
|---|---|---|---|
| PostgreSQL | uuid or CHAR(26) | 16 bytes / 26 bytes | Native uuid type needs binary conversion; CHAR(26) is human-readable |
| MySQL / MariaDB | BINARY(16) or CHAR(26) | 16 bytes / 26 bytes | BINARY(16) saves space; CHAR(26) for readability |
| SQLite | TEXT | 26 bytes | String comparison preserves sort order |
| MongoDB | String | 26 bytes | Lexicographic index on string field works correctly |
| DynamoDB | S (String) | 26 bytes | Sort keys using ULIDs give chronological ordering for free |
If you need to sort records by creation time, storing ULIDs as strings still preserves chronological order because Crockford Base32 maintains lexicographic sorting. This is the core advantage over UUID v4, where string sorting produces random order. When migrating from auto-increment integers to ULIDs, keep in mind that the ID column will grow from 4-8 bytes to 16-26 bytes, which affects index size on very large tables.
Language and Library Support
ULID libraries exist for virtually every major language. The JavaScript ulid package on npm has over 5 million weekly downloads as of early 2026, and 1,200+ packages in the npm registry depend on it. The Go implementation (oklog/ulid) is widely used in backend services, and Rust, Python, Java, C#, Ruby, and PHP all have mature ULID libraries. Most implementations support both standard and monotonic generation modes.
In the browser, this generator uses the crypto.getRandomValues() API for the random component, which provides cryptographically secure randomness. Node.js applications can use the same Web Crypto API or the crypto module. No external service or network request is needed - ULID generation is entirely local.
Practical Tips and Common Mistakes
A frequent mistake is comparing ULIDs in a case-sensitive context when the database collation is case-sensitive. Since Crockford Base32 is case-insensitive by design, always normalise to uppercase (or lowercase) before storage. Another common issue is generating ULIDs on machines with drifting clocks in distributed systems - if one server's clock is ahead by even a few seconds, its ULIDs will sort after IDs from other servers regardless of actual creation order. Use NTP synchronisation to keep clocks aligned.
When parsing ULIDs from user input, validate both the length (must be exactly 26 characters) and the character set (only Crockford Base32 characters). Reject any string containing I, L, O, or U, since those letters are excluded from the encoding. Also check that the timestamp component does not exceed 7ZZZZZZZZZ (the maximum valid timestamp), which corresponds to the year 10889.
For cryptographic purposes, note that the timestamp component of a ULID reveals when it was created. If creation time is sensitive information, ULIDs are not the right choice - a random UUID v4 would be better since it contains no embedded metadata. Similarly, the sequential nature of ULIDs means that an attacker who knows one ID can estimate the approximate timestamp range of nearby IDs.
To work with Unix timestamps directly, try the Unix timestamp converter. For generating secure random values, the hash generator covers SHA-256, SHA-512, and other algorithms.
Sources
- ULID Specification (github.com/ulid/spec)
- Douglas Crockford - Base32 encoding specification
- RFC 4122 - A Universally Unique IDentifier (UUID) URN Namespace
- RFC 9562 - Universally Unique IDentifiers (UUIDs v6/v7/v8)
- MDN - Crypto.getRandomValues() Web API
- ulid/javascript - Reference JavaScript ULID implementation
Frequently Asked Questions
What is a ULID?
A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier encoded as 26 Crockford Base32 characters. It embeds a 48-bit millisecond timestamp followed by 80 bits of randomness, making ULIDs both unique and naturally sortable by creation time.
Why use ULID instead of UUID?
ULIDs sort lexicographically by creation time, which makes database indexing much more efficient than random UUIDs. They are also shorter (26 vs 36 characters), case-insensitive, and avoid visually ambiguous characters.
Are ULIDs compatible with UUID columns?
ULIDs are the same 128-bit size as UUIDs. Many libraries can convert between the two formats, and some databases like PostgreSQL can store ULIDs as UUIDs with a simple binary conversion.
Can I extract the timestamp from a ULID?
Yes. The first 10 characters encode a 48-bit millisecond Unix timestamp. This tool automatically shows the decoded timestamp for each generated ULID.
What is Crockford Base32?
It is a Base32 encoding created by Douglas Crockford that uses the digits 0-9 and letters A-Z excluding I, L, O, and U. This avoids confusion between visually similar characters (like 1 and I, 0 and O).
Related Tools
Link to this tool
Copy this HTML to link to this tool from your website or blog.
<a href="https://toolboxkit.io/tools/ulid-generator/" title="ULID (Sortable Unique ID) Generator - Free Online Tool">Try ULID (Sortable Unique ID) Generator on ToolboxKit.io</a>