System DesignIntermediate7 min readPart 11 of 14

ID Generation

Every entity in a distributed system needs a unique ID: tweets, orders, messages, likes. The obvious answer, auto-increment, breaks at scale because it needs one shared counter. This tutorial walks through the ID approaches interviewers expect, from auto-increment to Snowflake, with the trade-offs of each.

Can you explain id generation out loud?

I'm Alex. Read this, then I'll interview you on a design problem and push on the parts you skip.

What a good ID system needsCore idea

Unique everywhereAcross the whole system, without writers having to coordinate.
Available and fastMillions of IDs per second, with no central bottleneck.
Index-friendlyRoughly increasing and small, so database indexes stay compact.
No information leakIDs should not reveal your total count or growth rate.

Option A: auto-increment (one database)Compare

Works while you have one database. Beyond that, replicas and multiple primaries fight over the same counter or hand out duplicates. Rule it out explicitly for a distributed system, and say why.

Option B: UUIDCompare

Generate a random 128-bit ID anywhere, with practically zero chance of collision.

Pros

No coordination, unique everywhere, hides volume, trivial to implement.

Cons

128 bits (twice as wide). Random order scatters inserts across a B-tree index, causing fragmentation and cache misses. No time order, which can matter for audit trails.

Option C: Redis INCR / ticket serverCompare

One Redis counter hands out IDs with INCR. Simple and fast, but Redis becomes a single point of failure unless replicated: if it is down, no IDs. Grabbing a range of IDs at once and handing them out locally removes the round trip per ID.

Reserve a block of 1000 IDs atomically (Lua)Text
-- INCRBY returns the counter AFTER adding, i.e. the end of the block
local last = redis.call('INCRBY', KEYS[1], 1000)
local first = last - 999
return { first, last }

Option D: Snowflake (the FAANG favourite)Pattern

A 64-bit ID built from three parts: a timestamp, a machine ID and a per-millisecond sequence number. Different machines and different milliseconds can never produce the same ID, so no coordination is needed.

1 — unused sign bit41 bits: timestamp (ms) — milliseconds since a custom epoch10: machine — up to 1,024 workers12: seq — 4,096 IDs per ms per machine
The 64-bit Snowflake layout (widths not to scale). Because time is in the top bits, IDs sort by creation time.
Snowflake generatorTypeScript
const EPOCH_MS = 1_700_000_000_000; // a custom start date

class Snowflake {
  private lastMs = -1;
  private seq = 0;
  constructor(private machineId: number) {} // 0..1023, from a config service

  next(): bigint {
    let now = Date.now() - EPOCH_MS;
    if (now === this.lastMs) {
      this.seq = (this.seq + 1) & 4095;          // 12-bit sequence
      if (this.seq === 0) {                      // used up this millisecond
        while (now <= this.lastMs) now = Date.now() - EPOCH_MS;
      }
    } else {
      this.seq = 0;                              // new millisecond
    }
    this.lastMs = now;
    return (BigInt(now) << 22n) | (BigInt(this.machineId) << 12n) | BigInt(this.seq);
  }
}

Time-ordered

Sorting by ID sorts by creation time, which keeps indexes compact.

~69 years of range

41 bits of milliseconds from your chosen epoch.

4,096 IDs/ms/machine

About 4 million per second per worker.

No coordination

Each node only needs a unique machine ID. The bit split is tunable.

Option E: base62 short codesPattern

For user-facing links you want short IDs, so convert a Snowflake or UUID to base62 (digits plus lowercase and uppercase letters). This is exactly how the URL shortener tutorial turns a 64-bit ID into a 7-character code.

Choosing: decision tableSummary

If you need…Choose
A single small databaseAuto-increment
Offline generation, zero coordinationUUID v4
Distributed, ordered, index-friendlySnowflake
A compact code users will seeSnowflake + base62

Common interview mistakesPitfalls

“Just use auto-increment”In a distributed system, you must address the single-counter bottleneck.
UUID without the index costExpect to be asked about fragmentation and performance.
Not knowing the Snowflake layoutName all four fields and their bit widths.
Ignoring clock skewSay how you handle a clock that goes backwards.
Not tying it to the featureA short URL, a tweet and an order have different needs.

In the interviewIn the interview

Frequently asked questionsFAQ

How collision-safe is snowflake across a fleet?

It is guaranteed unique as long as machine IDs are unique and the per-millisecond sequence never wraps. Clock skew is the real danger, which is why production snowflake implementations either wait for the clock to catch up or, on large jumps, reject requests until sync.

Is a snowflake ID safe to leak in URLs?

The timestamp bits do leak creation order and approximate write rate, which is why public-facing identifiers such as payment references sometimes get a random prefix or a base62-obfuscated encoding. For internal primary keys that same ordering is usually a feature, because it keeps index inserts local.

What is a hardware counter alternative to snowflake?

For uniqueness without ordering, hardware random and cryptographic generators back UUIDv4 and UUIDv7 implementations. For ordered IDs, systems lean on database-native monotonic counters such as PostgreSQL sequences or TiDB auto-increment replicated through raft. Snowflake remains the interview standard because it needs no extra infrastructure.

Now explain id generation to me out loud

I'll give you a design problem and push on the trade-offs, like a real interviewer.

Practice with Alex

Keep readingKeep reading

Ready to practice?

Reading is step one. Saying it out loud is step two.

Start a mock interview with Alex, get pushed on the parts you skip, and see your hiring signal right after.