UUIDs are the first tool most backend developers reach for when they need a unique identifier that isn't tied to a database sequence. They're baked into most languages, look sensible in a URL, and work without coordination between services. But the UUID spec defines several versions with different trade-offs, and picking the right one actually matters for large systems.
What a UUID is
A UUID (Universally Unique Identifier, also called GUID on Windows) is a 128-bit value, typically written as 32 hex digits in 8-4-4-4-12 groups. The four hex characters at positions 13–16 encode the version (1 through 7); the first character of the 17–20 group encodes the variant. Everything else is data whose meaning depends on the version.
Version 1: time and MAC
v1 encodes the current timestamp (100-nanosecond intervals since 15 October 1582) plus the host's MAC address plus a clock sequence. Guaranteed unique without coordination — but it leaks when and where each ID was generated, which is usually bad. A lot of enterprise databases still produce them out of habit.
Version 4: pure random
v4 fills 122 of the 128 bits with random data from a cryptographic RNG. The other 6 bits are fixed to identify it as v4. It's the default for most modern systems because it reveals nothing, is simple to generate (one line of code if crypto.randomUUID is available), and has a collision probability so small it doesn't matter in practice.
Version 7: time-ordered
v7 is newer (RFC 9562, published 2024). It starts with a millisecond-precision timestamp and fills the rest with randomness. The result is monotonically sortable — useful for database primary keys because v4 UUIDs produce awful index fragmentation, while v7 keeps inserts clustered. If your database library supports it, prefer v7 over v4 for primary keys; use v4 only when you need to hide creation time.
Collision probability
For v4, the pool is 2^122 — about 5 × 10^36. Generating a billion UUIDs per second for 85 years still gives a negligible chance of any collision. In practice, collisions in UUID v4 are caused by bad RNGs, not by running out of space. Always use crypto.randomUUID or crypto.getRandomValues, never Math.random.
UUID vs auto-increment
Auto-increment IDs are smaller (8 bytes vs 16), naturally sorted, and fast to index — but leak business data ("how many orders does this company process per day"), require coordination in distributed systems, and make cross-database merges painful. UUIDs are the opposite: opaque, coordination-free, large. Use auto-increment for internal tables where no ID leaves the database. Use UUIDs for anything user-visible or exchanged between services.
Storage notes
Always store UUIDs as a native binary type if your database supports it (UUID in Postgres, BINARY(16) in MySQL). Storing as VARCHAR(36) doubles the space and slows every index lookup by 2–3x. The hex-with-hyphens form is just for display.
