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.

Ad
Ad

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.

ComponentCharactersBitsPurpose
TimestampFirst 1048Millisecond Unix timestamp (sortable, extractable)
RandomnessLast 1680Cryptographic random data (uniqueness within the same millisecond)
Total26128Globally 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.

PropertyULIDUUID v4UUID v7
Length26 characters36 characters (with hyphens)36 characters (with hyphens)
EncodingCrockford Base32Hexadecimal with hyphensHexadecimal with hyphens
Sortable by timeYes - lexicographic sort = chronologicalNo - random orderYes - same principle as ULID
Timestamp extractableYes - millisecond precisionNoYes - millisecond precision
Random bits8012262
Total bits128128128
Case sensitiveNoNoNo
StandardCommunity spec (ulid/spec on GitHub)RFC 9562RFC 9562
Database index performanceExcellent (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 TypeInsert PatternIndex PerformanceQuery by Time Range
Auto-increment integerSequentialExcellentRequires a separate timestamp column
UUID v4RandomPoor (B-tree fragmentation)Requires a separate timestamp column
ULIDSequential (time-based)ExcellentBuilt in - filter or sort by ID prefix
UUID v7Sequential (time-based)ExcellentBuilt 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).

FeatureDetails
Character set0123456789ABCDEFGHJKMNPQRSTVWXYZ (32 characters)
Excluded: I, LToo similar to the digit 1 in many fonts
Excluded: OToo similar to the digit 0
Excluded: UAvoids accidentally spelling offensive words
Case insensitiveLowercase and uppercase decode identically
Maximum value7ZZZZZZZZZZZZZZZZZZZZZZZZZ (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 CaseWhy ULID Works Well
Database primary keysSequential inserts, no coordination needed, timestamp built in
Event sourcingEvents naturally sort by creation time without a separate sequence number
Distributed systemsGenerated independently on any node with no central counter
Log correlation IDsSorting by ID gives you chronological order for debugging
File and object namingFiles sort chronologically in directory listings
API idempotency keysUnique per request, sortable for audit trails
Microservice request tracingTrace 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.

DatabaseRecommended Column TypeSize on DiskNotes
PostgreSQLuuid or CHAR(26)16 bytes / 26 bytesNative uuid type needs binary conversion; CHAR(26) is human-readable
MySQL / MariaDBBINARY(16) or CHAR(26)16 bytes / 26 bytesBINARY(16) saves space; CHAR(26) for readability
SQLiteTEXT26 bytesString comparison preserves sort order
MongoDBString26 bytesLexicographic index on string field works correctly
DynamoDBS (String)26 bytesSort 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

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).

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>