UUID Beautifier

Common UUID Mistakes

6 Common UUID Mistakes Developers Make

UUIDs seem simple, but there are several subtle pitfalls that can lead to security vulnerabilities, performance degradation, and bugs. Here are the six most common mistakes — and how to avoid them.

Mistake 1: Using Math.random() Instead of a CSPRNG

Danger: Predictable UUIDs enable enumeration attacks and data scraping.

Math.random() is not cryptographically secure. Its output is deterministic given the same seed, and the internal state can be recovered with enough observation. Always use crypto.randomUUID() or a library backed by a CSPRNG.

// ❌ WRONG — predictable using Math.random()
function badUUID() {
  var template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
  var uuid = template.replace(/[xy]/g, function(c) {
    var r = (Math.random() * 16) | 0;
    var v = (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
    return v;
  });
  return uuid;
}

// ✅ CORRECT — cryptographically secure
var uuid = crypto.randomUUID();

Mistake 2: Treating UUIDs as Secrets

Warning: UUIDs are identifiers, not authentication tokens.

A UUID v4 with 122 random bits is excellent for uniqueness, but it should never be used as a password, API key, or session token. UUIDs are designed to be globally unique — not secret. They lack key features of proper authentication tokens: no HMAC, no expiration, no revocation mechanism.

Use purpose-built solutions for authentication: JWT tokens, OAuth 2.0, or session cookies with server-side validation.

Mistake 3: Storing UUIDs as Strings in Databases

Storing UUIDs as CHAR(36) wastes over twice the storage and slows down index lookups compared to the native UUID type. In PostgreSQL, always use the native uuid type. In MySQL, use BINARY(16) with UUID_TO_BIN().

Storage Type Size per Row 1M Rows Total
CHAR(36) or TEXT 36+ bytes ~34 MB
Native UUID / BINARY(16) 16 bytes ~15 MB

Mistake 4: Case-Sensitive Comparisons

UUIDs can be represented in upper or lowercase hex. The standard does not specify a canonical case, which means 3A2E6B1F-... and 3a2e6b1f-... represent the same UUID but will fail a case-sensitive string comparison. Always normalize to lowercase before comparing UUIDs as strings, or use a UUID parser that handles comparison correctly.

// ❌ WRONG
if (uuidA === uuidB) { /* ... */ }

// ✅ CORRECT
if (uuidA.toLowerCase() === uuidB.toLowerCase()) { /* ... */ }

Mistake 5: Not Validating UUID Input

When accepting UUIDs from users, APIs, or URLs, always validate them before use. An unvalidated string passed to a database query or file operation could cause errors or unexpected behavior. Use a regex or a UUID parsing library:

const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;

function isValidUUID(str) {
  return UUID_REGEX.test(str);
}

Mistake 6: Using Random UUIDs as Clustered Primary Keys Without Care

In many databases (especially SQL Server and MySQL/InnoDB), the primary key doubles as a clustered index, which physically orders rows on disk. Inserting random UUID v4 values means each new row is likely to land somewhere in the middle of the table, causing page splits, fragmentation, and slower writes. The fix: use UUID v7 (time-ordered) or a separate clustered index on a time-based column.

Further Reading

We use cookies for theme preferences, analytics, and advertising. Read our Privacy Policy