Designing Snowflake-Style IDs: Ordering, Workers, and Clock Rollback
A random UUID is easy and it scatters across a B-tree. An auto-increment integer is ordered and it requires a single writer. A Snowflake-style id is the compromise Twitter published: a 64-bit value a machine can mint locally, roughly sorted by time, unique as long as you obey two rules.
The layout
One bit is left at zero so the value stays positive. The rest, in the original layout:
| Bits | Field | What it buys |
|---|---|---|
| 41 | Milliseconds since a custom epoch | About 69 years of range, and time order |
| 10 | Worker id | 1024 machines issuing at once |
| 12 | Sequence | 4096 ids per millisecond per worker |
Some deployments split the 10 bits into a datacenter and a worker. The math is the same. The sequence resets when the millisecond changes. If a worker needs a 4097th id in the same millisecond, it waits until the clock ticks. It does not overflow into the next worker's numbers.
Uniqueness is local. Two workers never share a worker id, and one worker never reuses a sequence inside a millisecond. No database round trip on the hot path.
The clock is part of the id
The timestamp is not decoration. If the clock steps backwards, the generator will hand out a timestamp it has already used, and the sequence may collide with an id that already left the process. NTP stepping a VM backwards is a real way to do this. The safe behavior is to refuse, or to wait until wall time catches the last timestamp you issued. Issuing into the past is a collision.
Worker ids have the same uniqueness problem across process restarts. A random 10-bit number will collide. Lease the id: a row with a TTL that the process renews, or the ordinal of a StatefulSet whose size stays under 1024. When the process dies, the lease expires and the id can be reused, but only after any id it minted is already in the past relative to the timestamp width you care about. Reusing a worker id in the same millisecond is the collision. A lease measured in seconds, and a generator that will not issue with a timestamp older than its start, is enough.
What the id is not
It is roughly ordered, not totally ordered. Two ids from different workers in the same millisecond compare by worker id, not by which request arrived first. Do not use the sort as a happens-before relationship.
It does not fit in a JavaScript number. Numbers are safe up to 2^53, and this id is larger. JSON APIs send it as a string. Clients that parse it into a number will silently round it, and the next GET will 404.
It encodes the creation time to anyone who knows the epoch. That is fine for an order id. It is the wrong primitive for a secret, a password-reset token, or an unguessable link. It is also not an idempotency key. A retry that mints a new id is a second write. The key has to come from the client and stay stable across the retry, which is the design in idempotency keys for write APIs.
Keep reading
Write Skew: The Anomaly Snapshot Isolation Does Not Catch
Two transactions each read what the other writes, both commit, and an invariant dies. Snapshot isolation allows write skew — here is how to close the hole.
Designing a Shopping Cart: Price Snapshots, Merge, and No Inventory Hold
A cart is a per-user document, not a reservation. What to store on the line, how to merge an anonymous cart at login, and when the price is allowed to change.
PostgreSQL 19 on October 29: WAIT for Read-Your-Writes, REPACK Without the Lock, and What Got Pulled
PostgreSQL 19 GA is scheduled for October 29, 2026. The WAIT command gives standbys read-your-writes, REPACK CONCURRENTLY replaces VACUUM FULL and CLUSTER, autovacuum goes parallel, and SQL/PGQ, online checksums, and FOR PORTION OF were reverted in Beta 4.
Idempotency Keys for Write APIs
How to make POST safe to retry: the key, the stored response, the race between two identical requests, and the expiry that forgets too soon.
Read-Your-Writes: The User Just Saved and the Read Replica Does Not Know
Why a write to the primary followed by a read from a replica shows stale data, and the practical ways to pin the next read without sending all traffic to the primary.
Designing Chat Presence: Online, Away, and the Lie of Instant Status
Heartbeat vs subscriptions, fan-out of presence, privacy, and why a boolean online flag does not survive a million concurrent sockets.
Newsletter
New posts, straight to your inbox
One email per post. No spam, no tracking pixels, unsubscribe anytime.
Comments
- No comments yet. Be the first.