Approach 5: Twitter Snowflake
In one line: Snowflake is the design people actually deploy, and its bit layout is the most commonly asked detail in this entire topic. Being able to allocate the 64 bits and justify each field is the deliverable.
The bit layout
Time first is what makes the ID sortable: comparing two IDs numerically compares their timestamps before anything else.
1 bit 41 bits 10 bits 12 bits [sign] [timestamp ms] [worker] [sequence] 0 0010100100... 1010 000000000001 1 + 41 + 10 + 12 = 64 bits
| Field | Bits | Purpose |
|---|---|---|
| Sign bit | 1 | Always zero, ensuring the ID is interpreted as a positive integer |
| Timestamp | 41 | Milliseconds since a chosen epoch — provides the time ordering |
| Worker number | 10 | Supports 2^10 = 1,024 worker IDs — distinguishes machines |
| Sequence number | 12 | 2^12 = 4,096 IDs per millisecond per worker; resets to zero every millisecond |
Each field answers one of the previous lesson's failures. The sequence fixes same-millisecond collisions on one server. The worker fixes cross-server collisions. The timestamp provides ordering. The sign bit just keeps the number positive so it sorts correctly as a signed integer.
The epoch
Snowflake uses a default epoch of 1288834974657 (Nov 4, 2010), but systems can define a custom epoch — for instance Jan 1, 2022.
Time to range depletion = 2^41 identifiers
/ (365 * 24 * 60 * 60 * 1000 identifiers/sec)
~= 69 years
This 41-bit range allows for 69 years of IDs.
Decoding a real Snowflake ID
Worth walking end to end, because it makes the layout concrete:
Step 1 — read the 41 timestamp bits as a decimal:
352,721,356,343
Step 2 — add the Twitter epoch:
352,721,356,343 + 1,288,834,974,657 = 1,641,556,331,000
Step 3 — interpret as milliseconds since the UNIX epoch:
1,641,556,331,000 ms -> Jan 07 2022 11:52:11 UTC
The timestamp field is a delta from the epoch, not an absolute UNIX time — which is exactly why the epoch choice matters and why two systems with different epochs produce incomparable IDs.
Pros and cons
| Detail | |
|---|---|
| Pros | IDs are time-sortable and the generator is highly available |
| Cons | The 41-bit timestamp limits the system's lifespan (approx. 69 years). This range is consumed by the passage of time, regardless of how many IDs are actually generated |
That second point is subtle and worth stating: the timestamp budget drains on a wall clock, not on usage. A system generating ten IDs a day exhausts its 41 bits at exactly the same moment as one generating billions.
The deeper weakness: physical clocks are unreliable
Clock error can be as high as 17 seconds per day. On a single server that does not matter — every transaction lands on the same machine, so the ordering is internally consistent. In a distributed environment the clocks won't remain synced, and no matter how often you synchronize, there will always be skew between the clocks in the system.
The concrete failure: if a server's clock drifts forward, it generates IDs for a future time. When NTP recalibrates the clock backwards, the server may generate duplicate timestamps or violate causality — reissuing a millisecond it has already used.
NTP synchronizes clocks over variable-latency networks, aiming to keep computers within milliseconds of UTC, but it is susceptible to network latency and security issues. Even with high-resolution clocks, the risk persists — which is why Snowflake scores only weak on causality.
What if a worker exceeds 4,096 IDs in one millisecond?
The sequence field wraps. The standard behavior is to wait until the next millisecond before issuing more — the generator blocks briefly rather than reusing a sequence number.
That is the right trade: a sub-millisecond stall is preferable to a duplicate ID. If a single worker genuinely needs more than 4 million IDs per second sustained, the answer is more workers, not more sequence bits — you have 1,024 of them available.
Where does a worker get its ID?
The ten worker bits assume every generator already knows a number nobody else is using. The design does not say how, and that omission is the most common Snowflake failure in practice — because the failure mode is silent.
Four ways to assign the number, and they are not equivalent:
| Approach | How | Where it breaks |
|---|---|---|
| Static configuration | A number baked into each machine's config | Fine for a fixed fleet; breaks under autoscaling, where machines appear without a human to assign one |
| Derived from the host | Hash the IP or hostname down to ten bits | No coordination, but hashing to 10 bits collides — and a collision is silent duplicate IDs |
| Coordination service | A sequential ephemeral node in ZooKeeper or etcd; the node's index is the worker ID | Correct and the standard answer. Costs a dependency at startup only — once a worker holds its ID, generation is coordination-free |
| Leased ID | Same, but the ID is a lease the worker renews | Handles the hard case: a worker that hangs and resumes has to discover its lease expired and stop |
The property that makes the coordination-service answer acceptable is worth stating: the coordination happens once, at startup, not per ID. That is the same "amortize the coordination" move as the range handler earlier in the chapter — pay a coordinated cost rarely, then run free.
When the clock goes backwards
The chapter has established that clocks drift and NTP corrects them. The practical question is what a running generator does at the moment it notices, and it needs a decided answer rather than an assumption.
The first option is the one to name and reject: issuing anyway is how Snowflake produces duplicates, and it does so silently.
Between the other two, the practical rule is by magnitude. A small rollback — a few milliseconds, ordinary NTP correction — is best handled by waiting, since the stall is shorter than any alternative. A large rollback, seconds or more, means something is genuinely wrong with that machine, and the right move is to refuse to issue and fail loudly rather than block for seconds while pretending to be healthy.
Both are better than the option candidates usually reach for, which is to keep a monotonic counter and ignore the clock — because that quietly turns a time-sortable ID into a not-quite-time-sortable one, and nothing tells you it happened.
The general principle: a system that derives correctness from the clock needs an explicit answer for the clock being wrong. "We assume NTP keeps it accurate" is an assumption, not a design.
Scorecard
| Unique | Scalable | Available | 64-bit numeric ID | Causality maintained | |
|---|---|---|---|---|---|
| Using a range handler | |||||
| Using UNIX timestamps | weak | weak | |||
| Using Twitter Snowflake | weak |
Four solid columns and a weak on causality — because the ordering it provides is only as good as the clocks producing it.
Key takeaway
Snowflake is a bit-budget allocation problem solved well: time for ordering, worker for machine identity, sequence for intra-millisecond concurrency. Two things the layout does not specify and you must: how a worker gets its ID — a sequential ephemeral node in a coordination service, paid once at startup rather than per ID, because a duplicated worker ID produces duplicate IDs silently — and what the generator does when the clock moves backwards, where waiting is right for small rollbacks and failing loudly is right for large ones. Its remaining flaw is inherited from physical time, which is what logical clocks address next.
Interview signal by level
| Level | What a strong answer sounds like |
|---|---|
| L4 | "Use Snowflake IDs — they're time-sortable." |
| L5 | Gives the layout: "1 sign bit, 41 timestamp, 10 worker, 12 sequence — 4,096 IDs per millisecond per worker across 1,024 workers." |
| Staff+ | Justifies each field and names the flaw: "the sequence fixes same-millisecond collisions, the worker fixes cross-server ones. I'd set a custom epoch so we don't spend years of the 41-bit budget before launch. And the ordering is only as trustworthy as the clocks — an NTP correction backwards can reissue a millisecond, which is why this is weak on causality rather than solved." |
Next: ordering without trusting clocks at all.