Understanding ULID: A Better Alternative to UUID
ULID (Universally Unique Lexicographically Sortable Identifier) combines a millisecond-precision timestamp with high-entropy randomness to produce 128‑bit, URL‑safe, lexicographically sortable IDs that avoid UUID’s collision risks, offering advantages such as monotonic ordering, compact Base32 encoding, and suitability for distributed database primary keys.
ULID (Universally Unique Lexicographically Sortable Identifier) is presented as an alternative to UUID (Universally Unique Identifier). Both are 128‑bit identifiers, but ULID adds a millisecond‑precision timestamp to the random component.
Why not choose UUID
UUID has five versions, each with drawbacks:
Version 1 requires a stable MAC address, which is impractical and vulnerable.
Version 2 replaces part of the timestamp with POSIX UID/GID, inheriting the same issue.
Version 3 uses MD5 hashing and needs a unique seed, leading to possible data‑structure fragmentation.
Version 4 is purely random and provides no additional information.
Version 5 uses SHA‑1 hashing with similar seed‑dependency problems.
Even UUID‑4, while random, still carries a non‑zero collision risk. ULID, by contrast, combines a timestamp (millisecond precision) with 80 bits of randomness, yielding 1.21×10²⁴ possible values per millisecond and effectively eliminating collisions.
ULID Features
ulid() 01ARZ3NDEKTSV4RRFFQ69G5FAV128‑bit compatibility with UUID.
1.21×10²⁴ unique ULIDs per millisecond.
Lexicographically sortable (alphabetical order).
Encoded as 26 characters (vs. UUID’s 36).
Uses Crockford’s Base32 for efficiency and readability.
Case‑insensitive.
URL‑safe (no special characters).
Monotonic ordering within the same millisecond.
ULID Specification
The current Python implementation (ulid‑py) follows the binary layout shown below.
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
Timestamp Randomness
10 chars 16 chars
48 bits 80 bitsComponents
Timestamp
48‑bit integer.
UNIX time in milliseconds.
Enough range to last until year 10889.
Randomness
80‑bit random number.
Cryptographically strong randomness is recommended.
Sorting
The leftmost characters must appear first; the rightmost characters last, using standard ASCII ordering. Sorting is not guaranteed within the same millisecond.
Encoding
ULID uses Crockford’s Base32 alphabet (0123456789ABCDEFGHJKMNPQRSTVWXYZ), which omits I, L, O, and U to avoid confusion.
0123456789ABCDEFGHJKMNPQRSTVWXYZBinary Layout and Byte Order
Components are encoded as 16 octets 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, removing the need for DB‑side key generation.
In distributed environments, substitute UUIDs with globally unique, millisecond‑ordered IDs.
Use the embedded timestamp for time‑based sharding or partitioning.
When millisecond precision is acceptable, sort records directly by ULID instead of a separate timestamp column.
Usage (Python)
Install the library:
pip install ulid-pyCreate a new ULID:
import ulid
ulid.new()
#The timestamp part (48 bits) is derived from time.time() with millisecond precision, while the randomness (80 bits) comes from os.urandom() .
Convert existing UUIDs to ULID:
import ulid, uuid
value = uuid.uuid4()
ulid.from_uuid(value)
#Create ULID from a specific datetime:
import datetime, ulid
ulid.from_timestamp(datetime.datetime(1999, 1, 1))
#Access components of a ULID object:
import ulid
u = ulid.new()
u.timestamp() # returns Timestamp object
u.randomness() # returns Randomness objectSource code and further documentation are available at the project's GitHub repository.
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.