UUID vs Snowflake
On this page
TL;DR. Snowflake is a 64-bit time-ordered ID that requires per-machine configuration; UUID v7 is a 128-bit time-ordered ID that requires zero coordination. For new systems, UUID v7 wins unless you specifically need 64-bit IDs (compact storage, integer-only databases).
What Snowflake is
Snowflake is a distributed ID generator developed by Twitter (now X) in 2010 and open-sourced. It produces 64-bit integers laid out as:
┌─────────────────────────────────────────────────────────────┐
│ 1-bit │ 41-bit timestamp │ 10-bit machine ID │ 12-bit seq │
│ sign │ (ms since │ (per-datacenter │ (within │
│ (0) │ epoch) │ + per-worker) │ same ms) │
└─────────────────────────────────────────────────────────────┘
- 41 bits of timestamp ≈ 69 years of precision
- 10 bits of machine ID = 1024 unique generators
- 12 bits of sequence = 4096 IDs per machine per millisecond
To use Snowflake, every ID-generating service needs an assigned, unique machine ID. Two services accidentally given the same machine ID will collide on every clock tick — there’s no built-in protection.
Side-by-side
| UUID v7 | Snowflake | |
|---|---|---|
| Bits | 128 | 64 |
| Timestamp | 48-bit Unix ms | 41-bit ms (custom epoch) |
| Random/seq | 74 random | 12-bit per-ms sequence + 10-bit machine ID |
| Coordination needed | none | each generator needs unique machine ID |
| Collision risk | astronomically low | guaranteed if two machines share ID |
| Native DB type | uuid everywhere | bigint |
| Storage size | 16 bytes | 8 bytes |
| Lexicographic sort | chronological | chronological (within process) |
| Standard | RFC 9562 | Twitter open-source spec |
Where Snowflake wins
- Compact storage. 8 bytes vs 16. For trillion-row tables, this halves the index size.
- Native integer. Works in databases that don’t have a UUID type. Indexed as a fast path on every engine.
- Decodable by humans with a small amount of code — given a Snowflake, you can quickly extract the timestamp and worker ID. (The same is true of v7, but UUIDs look more opaque.)
- Sequence-within-millisecond ordering is strict — within one process, Snowflake IDs are always strictly monotonic.
Where UUID v7 wins
- No coordination. v7 generators don’t need machine IDs. Two services on opposite sides of the planet generate v7 UUIDs that will never collide. With Snowflake, “machine ID assignment” is operational complexity you have to build.
- Standard ecosystem. UUID is in every database, every framework, every standard library. Snowflake needs a custom library and a custom column type (often
bigintwith a comment explaining what it is). - Cross-system identity. A UUID v7 in your database is the same value when emitted to Kafka, logged in Datadog, or returned to a mobile client. No “decode this Snowflake to know which datacenter generated it” needed.
- Mergeable systems. Acquire a company? Their UUIDs slot in. Their Snowflakes might collide with yours if their machine IDs overlap.
- No “broken at year 2080” surprise. Snowflake’s 41-bit timestamp wraps after ~69 years. UUID v7 has 48 bits → ~8900 years.
When Snowflake actually makes sense
- Existing systems already on bigint primary keys. Migrating Twitter-scale tables to UUID is a real cost; sticking with Snowflake-style 64-bit IDs preserves that.
- Database engines without native UUID support where you don’t want the storage overhead of strings.
- Memory-bound systems where the 8-byte difference matters at scale.
- You actively want machine ID embedded in every row for sharding / debugging.
For most new systems, none of these apply.
Code
Snowflake
There’s no official Twitter library; you pick one of many implementations. Sample (Go):
import "github.com/bwmarrin/snowflake"
node, _ := snowflake.NewNode(1) // machine ID 1
id := node.Generate()
fmt.Println(id.Int64()) // e.g. 1541815603606036480
The 1 you pass to NewNode is the machine ID. If two services pass 1, you collide.
UUID v7
import "github.com/google/uuid"
id := uuid.Must(uuid.NewV7())
No machine ID, no node configuration. Generators on different machines never collide.
Hybrid: Snowflake-like UUIDs
You can pack a Snowflake into a UUID v8 (custom layout):
v8 UUID: <40-bit ms timestamp> <8-bit machine ID> <16-bit seq> <4-bit ver=8> <2-bit var> <62-bit random>
This gives you Snowflake’s worker-ID + sequence semantics in a UUID-shaped value. v8 is in RFC 9562 specifically for this kind of customization. Most teams find it more complexity than they need; pick v7 unless you have a real reason.
What about ULID, KSUID, NanoID?
For the time-ordered identifier family broadly:
- ULID — 128-bit, base32, sortable, no central authority.
- KSUID — 160-bit, base62, sortable, has a longer timestamp range.
- Nanoid — short, random, not time-ordered.
- Snowflake — 64-bit, custom epoch, requires machine IDs.
- UUID v7 — 128-bit, hex, sortable, no central authority, RFC standard.
Snowflake’s main pitch was “compact and time-ordered” before UUID v7 existed. v7 closes the gap on time-ordering at the cost of double the bytes — usually worth it for the ecosystem support.
Decision flowchart
Are you building a brand-new system in 2026?
└── UUID v7 (RFC standard, no coordination, fits everywhere)
Are you migrating an existing Snowflake-based system?
└── Stay on Snowflake (migration cost > new-system benefit)
Are 8 bytes vs 16 bytes a real bottleneck?
├── Yes — at trillion-row scale → Snowflake or short ID + UUID hybrid
└── No → UUID v7
Do you need to embed machine identity in every ID?
├── Yes → Snowflake or v8 UUID
└── No → UUID v7
Try the tools
- UUID v7 generator — what most new systems should use
- UUID validator — paste any UUID, decode the timestamp
- UUID vs ULID — for the case where you want shorter strings
- UUID as primary key — DB design discussion