GeneratePass
LEXICOGRAPHICALLY SORTABLE

ULID Generator

Generate Universally Unique Lexicographically Sortable identifiers.

Timestamp (decoded) -
About ULID

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.

Comparison

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.

Practical Applications

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.

Key Advantage

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.

Security Warnings

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.

Common Questions

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.

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

Example 1: Generate a ULID for a database primary key with natural ordering
1

Click Generate to produce a 26-character Crockford Base32 string

2

Observe the first 10 characters encode the current timestamp (milliseconds since Unix epoch)

3

The remaining 16 characters are cryptographically random

4

Sort a batch of ULIDs and confirm they appear in chronological order

Result01ARZ3NDEKTSV4RRFFQ68GABC8 — timestamp: 01ARZ3NDEK (milliseconds since epoch), random: TS4RRFFQ68GABC8
Example 2: Generate multiple ULIDs and verify time-ordered sorting
1

Click Generate 5 times with short delays between clicks

2

Record each ULID and its generation timestamp

3

Sort the ULIDs alphabetically (ascending)

4

Confirm the alphabetical sort order matches the chronological generation order

Result01ARZ3NDEK → 01ARZ3NDEL → 01ARZ3NDEM → 01ARZ3NDEN → 01ARZ3NDEO — alphabetical sort = chronological sort

Code Examples

javascriptGenerate a ULID with timestamp prefix and random suffix
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);
javascriptExtract timestamp from a ULID
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

ComponentBitsCrockford CharsContentExample
Timestamp4810Milliseconds since Unix epoch01ARZ3NDEK
Random4816Cryptographically random bitsTS4RRFFQ68GABC8
Total9626Crockford Base32 encoded01ARZ3NDEKTS4RRFFQ68GABC8

ULID vs Other Sortable IDs

ID TypeLengthSort OrderEntropyResolution
ULID26 charsLexicographic128 bits total (80 timestamp + 48 random)1 millisecond
UUIDv736 charsLexicographic122 bits random portion1 nanosecond
Snowflake~20 charsNumeric64 bits1 millisecond
ObjectID (Mongo)24 charsLexicographic80 bits total1 second
KSUID27 charsLexicographic128 bits1 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

01

Database primary keys in write-heavy systems where time-ordered inserts reduce B-tree page splits and improve cache locality.

02

Time-series data ingestion where ULID enables range queries without a separate timestamp column.

03

Event sourcing and audit logs where chronological ordering of events must be embedded in the identifier itself.

04

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

Fundamentals

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.

Technical Deep Dive

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.

Practical Applications

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.

Security Pitfalls

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 Tools

Related Identifier Tools

Explore these unique identifier generation tools:

Frequently Asked Questions

How is a ULID different from a UUID?
UUIDs are 128-bit identifiers without embedded timestamps. ULIDs embed a timestamp in the first 48 bits, making them lexicographically sortable. ULIDs are also shorter (26 chars vs 36 chars) and use URL-safe encoding. Use ULIDs when time-based sorting is important.
Can ULIDs be sorted chronologically?
Yes. Because the timestamp occupies the most significant bits, ULIDs sort lexicographically in chronological order. This makes them ideal for database indexes, log entries, and any application where insertion order matters.
What is the timestamp precision of a ULID?
ULIDs use millisecond precision from the Unix epoch. This provides approximately 8,900 years of unique timestamps (from 1970 to 10,889 AD). Multiple ULIDs generated within the same millisecond are distinguished by their random component.
Are ULIDs URL-safe?
Yes. ULIDs use Crockford's Base32 encoding, which contains only alphanumeric characters (0-9, A-H, J-K, M-N, P-T, V-Z). No URL encoding is required, making them safe for URLs, filenames, and other contexts where special characters cause problems.
Should I use ULIDs for API keys?
No. ULIDs embed timestamps, which leak information about when they were created. For API keys and security tokens, use purely random identifiers like UUID v4, NanoID, or dedicated secret token generators that do not contain timestamp information.