Q: Unique ID generation — UUID, Snowflake, ULID, KSUID. Pick one.

Answer:

Every distributed system needs IDs. The naive auto_increment doesn't work across nodes; UUID v4 is random but unsorted. Modern choices like Snowflake, ULID, UUIDv7 combine uniqueness, sortability, and decentralization.

Requirements for a Good ID

  • Unique: no collisions across distributed generators.
  • K-sortable: rough time-ordering helps DB indexes and pagination.
  • Compact: 16 bytes is fine; 64-bit is great.
  • Stateless generation: no coordination per ID.
  • Opaque externally: don't leak business semantics.

Options

SchemeBitsSortableCoordinationNotes
auto_increment32–64yesDB row lockCentralized
UUID v1128partial (MAC-time)noneLeaks MAC address
UUID v4128NO (random)noneUniversal default but unsortable
UUID v7128yes (time-ordered)noneNew; modern default
Snowflake64yesmachine-id configTwitter's scheme
ULID128yesnoneURL-safe encoding
KSUID160yesnoneSegment's scheme
NanoIDconfigurablenononeURL-safe random; like UUIDv4

UUID v4

hex: f47ac10b-58cc-4372-a567-0e02b2c3d479

128 bits, 122 of randomness. Collision probability negligible.

Cons:

  • Not time-ordered → bad for DB index locality (random inserts → page splits in B-tree).
  • Larger than 64-bit IDs.
  • Hard for humans to glance.

UUID v7

018f8d34-... (first 48 bits = ms timestamp; rest random)

Released as draft-2024, in mainstream libs (Postgres uuid_generate_v7() via extensions).

Pros:

  • 128 bits like UUID.
  • Time-ordered: index locality, easy "newest first" sort.
  • Drop-in replacement for UUID v4.

The modern default for new systems. Combines UUID's universality with sortability.

Snowflake

64-bit ID:

| 1 sign | 41 timestamp (ms) | 10 machine_id | 12 sequence |
  • Timestamp: ms since epoch (Twitter's: 1288834974657).
  • Machine ID: configured per node (10 bits = 1024 machines).
  • Sequence: counter per ms per node.

Properties:

  • 64-bit, compact.
  • K-sortable (by timestamp).
  • 4096 IDs/ms/machine = 4M IDs/sec/machine.
  • Requires unique machine IDs.

Used by Twitter, Discord, Instagram (similar scheme).

Bookkeeping:

  • Machine IDs from etcd / ZK / DB.
  • Clock skew handling: refuse to generate if clock goes backwards.

ULID

128-bit, lexicographically sortable:

01H6FXM34VWCEK0NHJRA94QSEW
^^^^^^^^^^                  Crockford-base32 timestamp (48 bits)
          ^^^^^^^^^^^^^^^^   Random (80 bits)

Pros:

  • Time-ordered.
  • URL-safe.
  • No coordination.
  • Same size as UUID.

Library: lots; e.g., ulid in many languages.

KSUID (Segment)

20 bytes (160 bits):

27-char base62: 0o5sQohJzs8WW3hjwOyaCfaTeZB

Like ULID but bigger (more random bits → effectively no collision risk at any scale).

Sortability and DB Performance

B-tree primary key with random IDs (UUID v4):

  • Each insert → random page in the index.
  • Pages split, fragment, bloat.
  • Cache locality poor.
  • Insert-heavy workloads slow.

Sortable IDs (UUIDv7, ULID, Snowflake, auto_increment):

  • Each insert → end of index (last page).
  • Sequential writes; cache-friendly.
  • 2–10× faster insert throughput in benchmarks.

For new systems: use sortable IDs.

Cross-Region / Multi-DC

  • Snowflake: assign machine IDs per region (e.g., first 3 bits = region).
  • UUIDv7 / ULID: no coordination at all.
  • DB-managed auto_increment: doesn't work across regions.

Don't Expose Internal IDs

Sequential / sortable IDs leak:

  • Total count (/orders/12345 → estimate Twitter's order volume).
  • Creation order (privacy / business).

For external APIs: use opaque IDs (UUID or signed hashids). Internal: keep the sortable ones.

Choosing in 30 Seconds

External API URL identifier   → UUIDv4 or signed hashids
Internal primary key, new   → UUIDv7 or ULID
Already on Snowflake      → keep
Distributed numbering at extreme scale (10M+ IDs/sec)  → Snowflake-class
URL-friendly string         → ULID or NanoID

Common Mistakes

MistakeReality
UUID v4 PK on a big tableIndex bloat, slow inserts
Snowflake with same machine ID on multiple nodesDuplicate IDs
Exposing auto_increment in URLsLeaks order volume
Generating IDs in client codeTrust issues; clients can forge
Mixing schemes within one tablePainful migrations

[!NOTE] For 2025 greenfield work, default to UUIDv7 unless you specifically need 64-bit (Snowflake) or URL ergonomics (ULID). UUIDv7 is what UUID v4 should have been.

Interview Follow-ups

  • "How does Twitter generate IDs?" — Snowflake; each datacenter has a service that emits IDs with its assigned machine_id range.
  • "What if a node's clock jumps backward?" — Refuse to generate (Twitter's choice); panic vs reject; tolerate small skew via NTP.
  • "How do you migrate from int64 to UUID without downtime?" — Add UUID column nullable; backfill; flip writes to populate both; switch reads; drop old.