Five Unique ID Generators in Distributed Systems
Five ID generation patterns and the tradeoffs between order, scale, and coordination.
A distributed system needs more from an ID than uniqueness. The ID may need to sort by creation time, fit inside a 64 bit integer, avoid revealing business volume, survive partitions, and work without a bottleneck.
UUID
A UUID is attractive because each process can generate IDs locally with no round trip to another service. That removes a whole category of availability problems. If an API server can accept a request, it can usually mint the identifier too.
The tradeoff is shape. Random UUIDs such as UUIDv4 are very poor primary keys for B-tree indexes because inserts land across the index rather than near the end. That causes more page splits, worse cache locality, and larger secondary indexes. UUIDs also consume 128 bits, which is fine in most databases but still larger than a 64 bit integer. Uniqueness is probabilistic rather than absolute, although collisions are rare enough that most systems treat them as negligible. Newer time-ordered variants such as UUIDv7 reduce index fragmentation, but they still keep the larger key size.
Snowflake
Snowflake-style IDs encode several fields into one integer, usually a timestamp, a worker identifier, and a per-millisecond sequence counter. A typical 64 bit layout might reserve 41 bits for time, 10 bits for worker ID, and 12 bits for sequence. That gives roughly time-sortable IDs while allowing each worker to generate many IDs in the same millisecond.
This is a good fit when you want fast local generation and ordered inserts. The hard part is co-ordination around worker identity and clock behaviour. If two nodes start with the same worker ID, or if the system clock moves backwards, duplicate IDs become possible unless the implementation blocks or refuses to issue IDs. Snowflake is fast, but it is only safe if node identity assignment and time discipline are treated as operational concerns.
Database auto-increment
The simplest centralised option is an auto-increment column in a relational database. It is easy to understand, transactionally safe within that table, and already integrated with most ORMs.
It also creates a dependency on the database path for every new record. That adds latency and makes the database part of the ID generation critical path. It is awkward in multi-region systems because one writer must remain the source of truth. Sequential numbers also leak information. If customer IDs jump from 81041 to 81091 in a minute, an outsider can infer growth or traffic.
Database segment
A segment allocator keeps the database as the source of truth but reduces contention by leasing ranges such as 1,000,000 to 1,009,999 to one application node and 1,010,000 to 1,019,999 to another. Each node then hands out IDs from memory until its range is exhausted.
This greatly lowers database write pressure and still gives compact numeric IDs. The cost is operational complexity. You need logic for range renewal, monitoring for near-empty segments, and safe recovery after restarts. Some IDs will be skipped when a process dies with an unused tail of its range. That is usually acceptable, but it surprises teams that expect perfect continuity.
Redis counters
Redis provides a lightweight central counter through commands such as INCR and INCRBY. Because Redis is memory-first, it is usually faster than hitting a transactional database row for each ID. It is a common choice when applications already depend on Redis and only need a global monotonically increasing number.
The weakness is durability and topology design. A single Redis primary is simple but becomes a dependency. Replication improves availability, yet failover timing matters: a primary can acknowledge increments that replicas have not applied yet. After failover, the new primary might continue from a lower value unless persistence and replication settings are chosen carefully. Redis also produces globally ordered numbers, which can leak volume just like database sequences.
The right choice depends on the constraint that matters most. UUID and Snowflake favour local generation. Database sequences favour simplicity. Segment allocation and Redis counters reduce hot spots, but both move risk into operations and failure handling.