ULIDs: The Superior Default for Your System's IDs, Inspired by Shopify

posted Originally published at byteaether.github.io 4 min read

Choosing the right unique identifier in a distributed system can feel like a minor detail, but it has massive consequences for database performance, scalability, and even how quickly you can debug a production incident. For years, we've reached for UUIDs, but their randomness can be a performance killer at scale.

This article explores why ULIDs (Universally Unique Lexicographically Sortable Identifiers) are a better default choice for most modern applications. We'll look at the tangible benefits Shopify discovered when they switched to ULIDs in their high-throughput payment infrastructure.

This is a shortened version of a more comprehensive article. For a deeper dive into the technical implementation, migration strategies, and performance benchmarks, read the full article on my blog, ByteAether.

What's a ULID and Why Is It Better?

A ULID is a 128-bit identifier, just like a UUID, but with a crucial design difference.

  • First 48 bits: A timestamp representing milliseconds since the Unix epoch.
  • Remaining 80 bits: Cryptographically secure random data.

A ULID looks like this: 01JJP9VSVRWSMP4QEJTYYFSJE8.

The first part (01JJP9VSVR) is the timestamp, and the second part (WSMP4QEJTYYFSJE8) is the random suffix. This simple structure gives ULIDs a superpower that UUIDs lack: they are lexicographically sortable. When you sort a list of ULIDs alphabetically, you are also sorting them chronologically by their creation time.

This one feature solves two of the biggest problems with traditional UUIDs.

The Trouble with UUIDs at Scale: Shopify's Story

Shopify's engineering team used UUIDv4 for idempotency keys in their payment systems—a critical feature to prevent accidentally charging customers twice. While UUIDs guaranteed uniqueness, their random nature created significant issues as transaction volume grew.

1. Database Performance Degradation

Databases like MySQL or PostgreSQL use B-tree indexes for fast data retrieval. These indexes work best with sequential data. When you insert a new record with a random UUID, the database has to find the right spot somewhere in the middle of the index to slot it in.

This causes frequent page splits, an expensive operation that fragments the index, slows down writes, and increases disk I/O. At Shopify's scale, this wasn't a theoretical problem; it was a measurable bottleneck causing latency in their critical payment pipeline.

2. Operational Complexity and Debugging Headaches

UUIDs are opaque; they contain no useful metadata. To figure out when a transaction with a specific UUID occurred, engineers had to perform extra JOINs on other tables or query for separate created_at timestamp columns. During a production incident, this added friction and complexity slows down root-cause analysis when every second counts.

The ULID Payoff: Shopify's Tangible Wins

Facing these challenges, Shopify switched from UUIDv4 to ULIDs for their idempotency keys. The results were immediate and impactful.

✅ 50% Faster Database Inserts

Because ULIDs are chronologically ordered, new records are simply appended to the end of the database index. This sequential write pattern is exactly what B-trees are optimized for. It dramatically reduced page splits and write latency. For their high-throughput systems, this simple change halved the time required for INSERT operations.

✅ Simplified Debugging and Observability

With ULIDs, the timestamp is embedded directly in the identifier. An engineer can instantly determine when a transaction occurred just by looking at the ULID. This eliminated the need for extra queries and made it far easier to correlate events and trace requests across logs and different services, significantly speeding up incident response.

✅ Reduced Storage and Schema Complexity

By relying on the embedded timestamp in the ULID, Shopify could remove redundant created_at columns from some of their tables. This streamlined their schema and cut down on storage overhead.

Why ULIDs Should Be Your New Default

Shopify's experience isn't unique. The benefits they saw apply to most modern applications, from event logging and real-time analytics to API development.

  • Performance: Sequential writes are a massive win for any write-heavy application. ULIDs eliminate the index fragmentation caused by random UUIDs, which is critical for scaling.
  • Built-in Observability: The embedded timestamp acts as free, context-rich metadata. It simplifies debugging, auditing, and data analysis without requiring extra columns or complex queries.
  • Sufficient Uniqueness: While UUIDv4 offers 122 bits of randomness to ULID's 80, the collision probability for a ULID is still astronomically low (about 1 in 1.2 x 10²⁴). For virtually all applications, this is more than enough to ensure global uniqueness.

UUIDs still have a place in niche scenarios where hiding an entity's creation time is a strict security requirement, but for the vast majority of systems, ULIDs offer a superior blend of features.

Conclusion: Evolve Your Identifiers

In modern system design, uniqueness alone isn't enough. Our identifiers must also support performance, observability, and scalability. ULIDs deliver on all these fronts by combining a sortable timestamp with strong randomness. As Shopify's success story demonstrates, making the switch can lead to tangible improvements in latency, operational efficiency, and developer experience.

Unless you have a specific reason to hide timestamps, ULIDs should be your default choice.

To learn more about Shopify's technical implementation, best practices for adopting ULIDs in your own systems, and a more detailed analysis, be sure to read the full, in-depth article on my blog.

0 votes
0 votes

More Posts

UUID vs ULID vs Integer IDs: A Technical Guide for Modern Systems

Joonatan Uusväli - Aug 6

Unifying Uniqueness and Order: Why ULIDs are the Future of Identifiers

Joonatan Uusväli - Jul 14

DevLog 20250520: Search Engine Architecture

Methodox - May 20

Building Credit Systems and User Management for AI Applications

horushe - Sep 21

Monoliths for Discovery, Microservices for Optimization

Steven Stuart - Nov 20
chevron_left