You know that moment when you hardcode Math.random() into a user ID and think “I’ll fix this later”?
Later arrives six months later as a production incident. The collision you thought would never happen has a name now: usr_a3f7b2.
UUIDs solve this. They’re a standard, globally unique, 128-bit identifier with libraries in every language. The tool that generates them takes 10 seconds to open.
The real problem isn’t UUIDs themselves — it’s knowing which version to use. UUID v4 (random) is the default in most libraries. Most developers never look further. Sometimes that’s fine. Often it’s not.
Here’s what each version actually does, and when to reach for which.
UUID Versions: What the Numbers Actually Mean
UUID v1 is time-based. It encodes the generating machine’s MAC address and a precise timestamp. Two UUIDs from the same machine sort in chronological order. Useful for time-series indexes. The catch: you’re encoding machine identity into a supposedly opaque identifier.
UUID v4 is random. 122 bits of entropy. The probability of generating the same UUID twice is so close to zero it might as well be zero. This is what most developers use. It’s safe, private, and works everywhere. Tradeoff: no chronological information, and new rows scatter unpredictably across database indexes.
UUID v5 is namespace-based. Pick a namespace (DNS, URL, OID, or X500), add a name string, then hash with SHA-1. The same namespace and name always produce the same UUID. Deterministic — useful for generating stable IDs from external data without exposing the original value.
The Version Table That Should Be in Every Code Review
| Version | Sortable | Deterministic | Privacy Risk |
|---|---|---|---|
| v1 (Time) | Yes | No | MAC address exposed |
| v4 (Random) | No | No | None |
| v5 (Namespace) | No | Yes | None |
When to Actually Use Each
Use v4 for: user records, session tokens, order IDs. Anything where the ID has no meaning beyond uniqueness.
Use v1 for: append-only logs or time-series databases where chronological ordering helps indexing, and you can accept encoding machine identity into the ID.
Use v5 for: integrating with external systems that have their own identifiers. Importing users by email from another platform? v5 generates a stable UUID from the email without ever exposing the email in the ID.
Stop Rolling Your Own ID Scheme
This is where the article should end, because the fix is simple:
// You're doing this
const id = 'usr_' + Date.now() + Math.random().toString(36)
// You should be doing this
import { v4 as uuidv4 } from 'uuid'
const id = uuidv4()
But you don’t need a library for this. Here’s the free browser-based tool that handles all three versions:
UUID Generator — pick version, pick count (1–100), copy output. No install. No dependency to maintain six months from now when the library you picked has a new major version.
The Debugging Trick Most Developers Never Learn
You can identify a UUID version at a glance in any log:
- v1 UUIDs show a timestamp pattern in the third hyphen-separated block — useful when you’re trying to figure out when something was created without querying the database
- v5 UUIDs are reproducible — the same namespace and name always produce the same ID, which means you can verify where an ID came from without storing the original mapping
When an ID conflict happens (rare, but it happens), the version tells you where to look: clock drift for v1, entropy failure for v4, namespace collision for v5.
The next time you reach for Math.random(), ask whether the UUID version you’re using is actually the right tool for the job.
