正在加载,请稍候…

UUID vs ULID: Which Unique ID Should You Use?

Compare UUID and ULID formats for database primary keys. Learn when to use each and generate them instantly.

What Is a Unique Identifier?

Unique identifiers (UIDs) are strings or numbers that uniquely identify records in a database, distributed system, or communication protocol. The two most common formats in modern software are UUID (Universally Unique Identifier) and ULID (Universally Unique Lexicographically Sortable Identifier).

Choosing the wrong format can lead to poor database performance, difficult debugging, or compatibility issues. This guide explains both formats and helps you decide which to use.

UUID: The Universal Standard

UUID is defined in RFC 4122 and consists of 128 bits displayed as 32 hexadecimal characters split by hyphens:

550e8400-e29b-41d4-a716-446655440000

UUID version 4 (the most common) uses random bits for all fields. It has approximately 122 bits of randomness — about 5.3 × 10³⁶ possible values. The probability of collision when generating 1 billion UUIDs is about 1 in 10²⁰.

UUID Version Source Use Case
v1 MAC address + timestamp Legacy, exposes device MAC
v3 MD5 hash of namespace + name Deterministic from name
v4 Random General purpose ✅
v5 SHA-1 hash of namespace + name Deterministic from name
v7 Unix timestamp + random Sortable, modern ✅

ULID: Sortable by Design

ULID encodes a 48-bit millisecond timestamp followed by 80 bits of randomness, displayed as 26 Crockford Base32 characters:

01ARZ3NDEKTSV4RRFFQ69G5FAV
│──────────│──────────────│
  10 chars     16 chars
  (timestamp)  (random)

Because the timestamp is the prefix, ULIDs sort lexicographically in chronological order. Records created at the same millisecond share a timestamp prefix but differ in the random suffix, preserving uniqueness.

Head-to-Head Comparison

Feature UUID v4 UUID v7 ULID
Length (string) 36 chars 36 chars 26 chars
Sortable
URL-safe Needs encoding Needs encoding
Contains timestamp
Standardized RFC 4122 RFC 9562 (2024) Community spec
Database index performance Fragmented Good Good
Readability Low Low Moderate

Database Performance: Why Sortability Matters

In B-tree indexes (PostgreSQL, MySQL), sequential inserts are far more efficient than random inserts. UUID v4's randomness causes index fragmentation: each new row is inserted at a random position in the index tree, causing frequent page splits and cache misses.

ULIDs and UUID v7 solve this by using monotonically increasing values (most of the time), which allows new records to be appended near the end of the index, dramatically reducing write overhead in high-throughput systems.

Benchmark data from various PostgreSQL experiments shows 3–5× better insert performance with sortable IDs on large tables (100M+ rows).

When to Use UUID v4

  • Maximum compatibility — Every database, language, and framework understands UUID.
  • No timestamp leakage — If you don't want creation time embedded in IDs.
  • Simple integration — Available in SQL (gen_random_uuid() in PostgreSQL 13+), Node.js (crypto.randomUUID()), Python (uuid.uuid4()).
  • Low-to-medium throughput — Fine for most applications with under millions of daily records.

When to Use ULID

  • High-write databases — Event sourcing, logs, audit trails.
  • URL-safe IDs — No hyphens or special characters.
  • Debugging — You can extract creation time from the ULID itself.
  • Sorted lists — Use as a cursor for pagination without storing created_at separately.

When to Use UUID v7

UUID v7 (formalized in RFC 9562, April 2024) offers the best of both worlds: standard UUID format with embedded Unix timestamp for sortability. It's increasingly supported in databases (PostgreSQL 17+) and libraries. For new projects, UUID v7 is often the best choice.

Practical Code Examples

// UUID v4 — Node.js built-in
const { randomUUID } = require('crypto');
const id = randomUUID(); // "550e8400-e29b-41d4-a716-446655440000"

// ULID — npm package
import { ulid } from 'ulid';
const id = ulid(); // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
-- PostgreSQL UUID v4
SELECT gen_random_uuid();

-- PostgreSQL UUID v7 (pg 17+ or pgcrypto extension)
SELECT uuid_generate_v7();

→ Try UUID Generator or ULID Generator