Fundamentals 8 min read

Why ULID Beats UUID: A Deep Dive into Unique, Sortable IDs

This article explains what ULID is, why it often outperforms UUID by combining timestamp and randomness for collision‑free, lexicographically sortable identifiers, details its specification, binary layout, encoding, and shows practical Python usage and common application scenarios.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Why ULID Beats UUID: A Deep Dive into Unique, Sortable IDs

ULID: Universally Unique Lexicographically Sortable Identifier

UUID: Universally Unique Identifier

Why Not Choose UUID

UUID currently has five versions:

Version 1 requires a unique, stable MAC address, which is impractical and vulnerable.

Version 2 replaces the first four timestamp bits with a POSIX UID or GID, inheriting the same issues.

Version 3 uses MD5 hashing; generating random IDs needs a unique seed, leading to data‑structure fragmentation.

Version 4 is based on random or pseudo‑random numbers and provides no additional information.

Version 5 uses SHA‑1 hashing with similar fragmentation concerns.

Version 4 is the most commonly used, but even random UUIDs carry a risk of collision. Unlike UUIDs, ULID combines a millisecond‑precision timestamp with a large random component (1.21 × 10²⁴ possibilities per millisecond), eliminating collision risk and producing a more readable string.

ULID Features

ulid() # 01ARZ3NDEKTSV4RRFFQ69G5FAV

128‑bit compatibility with UUID

1.21 × 10²⁴ unique ULIDs per millisecond

Lexicographically sortable (alphabetical order)

Encoded as 26 characters instead of UUID's 36

Uses Crockford's Base32 for efficiency and readability (5 bits per character)

Case‑insensitive

No special characters (URL‑safe)

Monotonic ordering to correctly handle IDs generated within the same millisecond

ULID Specification

The following shows the current ULID specification as implemented in the Python library ulid‑py. The binary format is defined.

01AN4Z07BY      79KA1307SR9X4MV3

|----------|    |----------------|
 Timestamp          Randomness
 10chars            16chars
  48bits             80bits

Components

Timestamp

48‑bit integer

UNIX time in milliseconds

Space will not be exhausted until year 10889.

Randomness

80‑bit random number

Cryptographically secure randomness is used when possible.

Sorting

The leftmost character must appear first and the rightmost last (lexicographic order). The default ASCII character set is required. Ordering cannot be guaranteed within the same millisecond.

Encoding

ULID uses Crockford's Base32, which excludes the letters I, L, O, and U to avoid confusion.

0123456789ABCDEFGHJKMNPQRSTVWXYZ

Binary Layout and Byte Order

Components are encoded as 16 octets, each in network byte order (big‑endian).

0               1               2               3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               32_bit_uint_time_high                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   16_bit_uint_time_low   |      16_bit_uint_random            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               32_bit_uint_random                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               32_bit_uint_random                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Application Scenarios

Replace auto‑increment primary keys in databases, eliminating the need for DB‑side key generation.

In distributed environments, replace UUIDs with a globally unique, millisecond‑ordered identifier.

Use the embedded timestamp for time‑based sharding or partitioning of tables.

If millisecond precision is acceptable, sort records directly by ULID instead of a separate created_at column.

Usage (Python)

Installation pip install ulid-py Create a brand‑new ULID. The 48‑bit timestamp is derived from time.time() with millisecond precision, and the 80‑bit random part comes from os.urandom().

>> import ulid
>>> ulid.new()
<ULID('01BJQE4QTHMFP0S5J153XCFSP9')>

Create a ULID from an existing 128‑bit value such as a UUID. Supported input types include int, bytes, str, and UUID.

>> import ulid, uuid
>>> value = uuid.uuid4()
>>> value
UUID('0983d0a2-ff15-4d83-8f37-7dd945b5aa39')
>>> ulid.from_uuid(value)
<ULID('09GF8A5ZRN9P1RYDVXV52VBAHS')>

Create a ULID from an existing timestamp (e.g., a datetime object). Supported timestamp types include int, float, str, bytes, bytearray, memoryview, datetime, Timestamp, and ULID.

>> import datetime, ulid
>>> ulid.from_timestamp(datetime.datetime(1999, 1, 1))
<ULID('00TM9HX0008S220A3PWSFVNFEH')>

Create a ULID from an explicit random value. Supported random types include int, float, str, bytes, bytearray, memoryview, Randomness, and ULID.

>> import os, ulid
>>> randomness = os.urandom(10)
>>> ulid.from_randomness(randomness)
<ULID('01BJQHX2XEDK0VN0GMYWT9JN8S')>

Once you have a ULID object, you can interact with it using various methods. The timestamp() method returns the 48‑bit timestamp snapshot, and the randomness() method returns the 80‑bit random snapshot.

>> import ulid
>>> u = ulid.new()
>>> u
<ULID('01BJQM7SC7D5VVTG3J68ABFQ3N')>
>>> u.timestamp()
<Timestamp('01BJQM7SC7')>
>>> u.randomness()
<Randomness('D5VVTG3J68ABFQ3N')>
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Distributed Systemsuuidunique identifierULID
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

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.