Fundamentals 6 min read

Understanding ULID: Features, Specification, and Python Usage

This article explains ULID (Universally Unique Lexicographically Sortable Identifier), compares it with UUID, outlines its technical specifications, lists its advantages and typical application scenarios, and provides detailed Python examples for generating and manipulating ULIDs.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Understanding ULID: Features, Specification, and Python Usage

ULID (Universally Unique Lexicographically Sortable Identifier) is presented as a modern alternative to UUID, offering a 128‑bit identifier that is both time‑sortable and highly random.

Unlike UUID, which has five versions with various drawbacks such as reliance on MAC addresses, time‑based collisions, or pure randomness, ULID combines a millisecond‑precision timestamp with 80 bits of randomness, yielding 1.21e+24 unique values per millisecond and eliminating collision risk while producing a more readable string.

Key ULID characteristics:

Compatible with the 128‑bit size of UUIDs

1.21e+24 unique IDs per millisecond

Lexicographically sortable (alphabetical order)

Encoded as a 26‑character string (vs. 36 for UUID)

Uses Crockford's Base32 for efficiency and readability

Case‑insensitive and URL‑safe (no special characters)

Monotonic ordering to correctly handle identical timestamps

The current ULID specification (as implemented in the ulid‑py Python library) defines a binary layout of 48 bits for the timestamp and 80 bits for randomness, encoded using Crockford's Base32 alphabet (0123456789ABCDEFGHJKMNPQRSTVWXYZ). The components are stored in network byte order.

Typical application scenarios include:

Replacing auto‑increment primary keys in databases, removing the need for DB‑side ID generation

Providing globally unique, millisecond‑ordered IDs in distributed systems as a UUID alternative

Embedding timestamps for easy time‑based sharding or partitioning of tables

Using ULID ordering for sorting records when millisecond precision is sufficient

Python usage example:

pip install ulid-py

Creating a new ULID:

>> import ulid
>>> ulid.new()

Converting from an existing UUID:

>> import ulid, uuid
>>> value = uuid.uuid4()
>>> ulid.from_uuid(value)

Creating a ULID from a specific timestamp:

>> import datetime, ulid
>>> ulid.from_timestamp(datetime.datetime(1999, 1, 1))

Creating a ULID from raw randomness:

>> import os, ulid
>>> randomness = os.urandom(10)
>>> ulid.from_randomness(randomness)

Once a ULID object is obtained, the timestamp() method returns the 48‑bit timestamp component, and the randomness() method returns the 80‑bit random component.

>> u = ulid.new()
>>> u.timestamp()
>>> u.randomness()

The reference implementation and source code are available at https://github.com/ahawker/ulid .

distributed systemsPythonunique identifierIdentifier GenerationULID
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.