ULID Generator

Universally Unique Lexicographically Sortable Identifiers — time-ordered, compact, and URL-safe.

Output
Click the value to copy
Tap/click to copy

What is a ULID?

A ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier encoded as a 26-character string using Crockford’s Base32 alphabet. ULIDs were designed to be a drop-in alternative to UUIDs that are inherently sortable by creation time, making them ideal for distributed systems, event sourcing, and database primary keys.

Unlike UUID v4 (which is entirely random), a ULID embeds a 48-bit millisecond-precision timestamp followed by 80 bits of cryptographically secure randomness. This means ULIDs generated later always sort after earlier ones — a property called lexicographic sortability.

ULID Structure

Every ULID is exactly 26 characters long and consists of two parts:

ComponentSizeCharactersDescription
Timestamp48 bits10 (positions 1–10)Unix time in milliseconds. Supports dates until the year 10889.
Randomness80 bits16 (positions 11–26)Cryptographically random. Up to 1.21 × 1024 unique ULIDs per millisecond.

The Crockford Base32 encoding uses the characters 0123456789ABCDEFGHJKMNPQRSTVWXYZ, which deliberately excludes I, L, O, and U to avoid ambiguity with digits and offensive words.

Key Features

  • Lexicographically sortable— ULIDs sort correctly as plain strings, making them perfect for database indexes and ordered logs.
  • 128-bit compatible— Same bit-width as UUID, so you can store ULIDs in existing UUID columns with no schema changes.
  • URL-safe & compact— 26 characters with no hyphens or special characters, compared to 36 for a standard UUID.
  • Case insensitive— Uppercase and lowercase are interchangeable; the canonical form is uppercase.
  • Monotonically orderable— Implementations can optionally increment the random component within the same millisecond to guarantee strict monotonic ordering.
  • No special characters— Safe for use in URLs, filenames, CSS selectors, and JSON keys without escaping.

ULID vs UUID v7

Both ULID and UUID v7 embed a millisecond timestamp for time-based sorting. The key differences are:

FeatureULIDUUID v7
EncodingCrockford Base32 (26 chars)Hexadecimal (36 chars with hyphens)
StandardCommunity specificationIETF RFC 9562
SortabilityLexicographic (string comparison)Lexicographic (string comparison)
Size on wire26 characters36 characters
EcosystemBroad library supportNative UUID tooling, RFC-backed

Choose UUID v7 when RFC compliance or seamless interoperability with existing UUID infrastructure is critical. Choose ULIDwhen you want shorter, URL-safe strings and don’t need to conform to the UUID format.

ULID vs UUID v4

UUID v4 is entirely random with no inherent ordering. While this is fine for many use cases, it causes B-tree index fragmentationin databases because inserts happen at random positions. ULIDs, being time-ordered, insert at the end of the index — dramatically improving write performance in high-throughput systems (PostgreSQL, MySQL, DynamoDB, etc.).

ULIDs also let you extract the creation timestamp directly from the identifier without a separate created_at column.

ULID vs Nanoid

Nanoid generates compact, random string IDs with a configurable alphabet and length. However, Nanoids have no time component and are not lexicographically sortable. If you need ordering by creation time, ULID is the better choice. If you need the shortest possible random ID, Nanoid wins.

When to Use ULID

  • Database primary keys— Especially in write-heavy workloads where index locality matters (PostgreSQL, MySQL, CockroachDB, DynamoDB).
  • Event sourcing & logging— Events naturally sort by time without an additional timestamp field.
  • Distributed systems— Generate unique, collision-resistant IDs across nodes with no coordination.
  • URL-safe identifiers— 26-character strings with no special characters work everywhere.
  • Message queues & streams— Time-ordered IDs simplify consumer processing and debugging.

Code Examples

JavaScript / TypeScript

import { ulid } from 'ulid'

// Generate a new ULID
const id = ulid()
// e.g. "01ARZ3NDEKTSV4RRFFQ69G5FAV"

// Monotonic factory — strictly increasing within the same ms
import { monotonicFactory } from 'ulid'
const monotonic = monotonicFactory()
const id1 = monotonic()
const id2 = monotonic() // guaranteed id2 > id1

// Extract timestamp
import { decodeTime } from 'ulid'
const ts = decodeTime('01ARZ3NDEKTSV4RRFFQ69G5FAV')
// ts = 1469918176385 (Unix ms)

Python

import ulid

# Generate a new ULID
new_id = ulid.new()
print(new_id.str)  # "01ARZ3NDEKTSV4RRFFQ69G5FAV"

# Extract timestamp
print(new_id.timestamp().datetime)

# From an existing ULID string
parsed = ulid.from_str("01ARZ3NDEKTSV4RRFFQ69G5FAV")
print(parsed.timestamp().int)  # Unix ms

Go

import "github.com/oklog/ulid/v2"

// Generate a new ULID
id, err := ulid.New(ulid.Timestamp(time.Now()), entropy)

// Parse and extract time
parsed, _ := ulid.Parse("01ARZ3NDEKTSV4RRFFQ69G5FAV")
fmt.Println(ulid.Time(parsed.Time()))