🧰 ToolPicoAll Tools →
HomeBlog › 5 Common UUID Mistakes Developers Make

5 Common UUID Mistakes Developers Make (And How to Avoid Them)

UUIDs look simple — 36 characters, a few hyphens, "unique enough." But there are a handful of mistakes that quietly show up in real codebases: the wrong storage type, a false sense of privacy, mixed-up hash algorithms, and validators that fail in confusing ways. Here are five worth checking your own code for.

In this guide

None of these mistakes are exotic — they're the kind of thing that works fine in a demo, then causes a slow index, a support ticket, or a confused code review six months later. Below is what tends to go wrong, and a practical way to check for it, illustrated with an ordinary example scenario: a small team building an internal tool that assigns IDs to imported records.

1. Storing UUIDs as plain text when a native type is available

Quick answer A 36-character text UUID takes roughly twice the storage of its 16-byte binary form and is generally slower to index and compare. If your database offers a native UUID or binary(16) column type, use it instead of VARCHAR(36).

It's an easy default: a UUID looks like a string, so it gets a VARCHAR(36) column. This works, but it isn't free. As a hypothetical example, imagine a table with 5 million rows using a text UUID primary key versus the same table with a native binary UUID type — the text version's index will typically occupy noticeably more disk space and can be slower to compare byte-by-byte during joins, simply because the database is treating a fixed-size 128-bit value as variable-length text. PostgreSQL has a dedicated uuid type; MySQL commonly stores UUIDs as BINARY(16) (sometimes reordered for better index locality); most ORMs can map a UUID field to whichever native type the underlying database supports. If your platform doesn't have a native type, at minimum store the value without hyphens or braces to save a few bytes per row.

2. Assuming a v1 UUID is privacy-safe because it "looks random"

Quick answer A genuine v1 UUID embeds the exact creation timestamp and, on real hardware, can embed the device's MAC address in its node field. It is not designed for privacy-sensitive contexts, even though it doesn't look meaningfully different from a v4 UUID at a glance.

This is a case where the string itself gives no visual warning. A v1 and a v4 UUID are both 36 characters of hex and hyphens, and to a human eye they look equally "random." But under the hood a v1 UUID's first three groups encode a 100-nanosecond-precision timestamp, and its node field can carry a real MAC address if generated by software following the original spec on physical hardware. That means a leaked v1 UUID can, in principle, reveal roughly when a record was created and which machine generated it — information a v4 UUID never carries. If you're issuing IDs that end up visible to end users (order numbers, share links, public API IDs), v4 or v7 is the safer default; reserve v1-style generation for internal systems where that extra information isn't a liability. Note that a browser-based generator can't access a real network card at all, so any "v1-like" mode there necessarily substitutes a randomly generated node value — which closes the MAC-leak issue specifically, but the embedded timestamp is still present.

Practical check: if you're not sure which version an existing ID column uses, decode a few sample values with a validator that reports the version nibble — don't assume from the format alone.

3. Mixing up v3 (MD5) and v5 (SHA-1) across a system

Quick answer v3 and v5 are both deterministic name-based UUIDs, but they use different hash functions and will NOT produce the same output for the same input. If different parts of a system pick different versions for what's supposed to be the same ID scheme, lookups silently stop matching.

Consider a hypothetical scenario: a data pipeline generates a deterministic ID for each imported product by hashing a namespace UUID together with the product's SKU. If the import script uses v5 (SHA-1) but a downstream reconciliation job was written months later using v3 (MD5) — perhaps because a developer copied an old code snippet — the two systems will generate different UUIDs for the identical SKU, and matching records will simply fail to line up. Nothing throws an error; the IDs are just quietly wrong. Since v5 is generally recommended over v3 for new work (SHA-1 has fewer known weaknesses than MD5, even though neither is being used here for cryptographic security), it's worth standardizing on v5 explicitly in code comments or a shared constant, rather than leaving the algorithm choice implicit.

4. Fighting format mismatches instead of normalizing on the way in

Quick answer UUIDs show up in the wild in several equally valid shapes — with or without hyphens, wrapped in braces, prefixed with urn:uuid:, upper or lower case. Comparing them as raw strings without normalizing first is a common source of "why doesn't this match" bugs.

A UUID's canonical form is 36 characters (8-4-4-4-12, lowercase, hyphenated), but plenty of systems hand you something else: a .NET API might return one wrapped in braces, a URI might carry a urn:uuid: prefix, a spreadsheet export might strip hyphens, and a case-insensitive system might return uppercase hex. If your code compares two UUID strings directly without stripping braces/prefixes and lowercasing both sides first, values that are logically identical can compare as unequal. The fix is to normalize on input — strip non-hex formatting characters, lowercase, and re-insert hyphens in the standard positions — rather than special-casing every format you happen to encounter later. A validator that accepts multiple input shapes (hyphenated, non-hyphenated, braced, urn-prefixed) and reports back the canonical form is a fast way to check whether two values you suspect are "the same UUID" actually are.

5. Misjudging collision risk in either direction

Quick answer Random UUIDs (v4) and time-ordered UUIDs (v7) have a collision probability low enough to ignore in essentially all practical applications. Name-based UUIDs (v3/v5), by contrast, are supposed to collide whenever the same namespace and name are reused — that's a feature, not a bug, and shouldn't be treated as an error condition.

There are two opposite mistakes here. The first is over-worrying about v4 collisions — for example, adding a "check if this UUID already exists" retry loop for newly generated v4 IDs as if collisions were a realistic operational concern; with 122 random bits, that safeguard adds complexity without meaningfully improving reliability for the vast majority of applications. The second, subtler mistake is treating a v3/v5 "collision" as a bug: if your deterministic ID generator produces the exact same UUID for the exact same namespace+name input every single time, that's the entire point of using a name-based version instead of a random one — it's what allows a re-run import job to recognize "I've already created an ID for this record" instead of creating duplicates.

Generate or validate UUIDs to check your own IDs Free, runs entirely in your browser — v4, v1-like, v3/v5, v7, and ULID, with a validator that decodes version, variant, and embedded timestamps. Try the free UUID Generator →

Frequently asked questions

Should I store UUIDs as a string or a binary column?
When your database supports it, prefer a native UUID/binary type (such as PostgreSQL's uuid column, or a 16-byte binary column) over plain text. Storing a UUID as a 36-character string wastes roughly twice the space of a 16-byte binary representation and is typically slower to index and compare, since the database has to treat it as an arbitrary string rather than a fixed-size value.
Does a v1 UUID reveal my MAC address or IP address?
A genuine v1 UUID, generated per the original RFC 4122 spec on a real machine, can embed the network card's MAC address in its node field, plus the exact creation timestamp — which is why v1 is generally avoided for anything user-facing or privacy-sensitive. A browser-based generator cannot read a real MAC address at all, so a "v1-like" tool typically substitutes a randomly generated node value with the multicast bit set, which avoids the MAC-leak problem but still exposes a creation timestamp.
What happens if I accidentally use MD5 (v3) instead of SHA-1 (v5)?
Nothing breaks technically — v3 and v5 use the same namespace+name construction, just a different hash function, and both produce valid, deterministic UUIDs. The practical risk is consistency: if part of your system generates v3 IDs for a given name and another part generates v5 IDs for the same name, they will NOT match, because the two algorithms produce different output for identical input. Pick one version and use it everywhere for a given ID scheme.
Why did my UUID validator say a value is invalid even though it looks right?
The most common cause is a formatting mismatch: extra whitespace, a missing or extra hyphen, wrapping braces or a urn:uuid: prefix that wasn't stripped, or a version/variant bit combination that doesn't correspond to any defined UUID version. A validator checks not just that the string is 32 hex characters, but that the version nibble and variant bits fall into a recognized pattern — a string that's the right length but has corrupted bits there will correctly be flagged as not a standard UUID.
Can two different tools generate the same UUID by accident?
For random UUIDs (v4) or time-ordered ones (v7), the chance of an accidental collision between two independent tools is astronomically small and not a practical concern. For name-based UUIDs (v3/v5), it's actually expected and desired: two different tools using the same namespace, the same name, and the same algorithm version will deterministically produce the identical UUID every time, by design.

Related guides

About this guide: This article describes general engineering patterns and illustrative, hypothetical scenarios for informational purposes; it does not cite specific benchmark numbers and is not a substitute for testing storage, privacy, and ID strategies against your own system and requirements.