🆔
Developer Tools
March 20, 20268 min readBy BrowseryTools Team

UUIDs, NanoIDs, and CUIDs: Choosing the Right ID Format for Your Project

A deep dive into UUID v1, v4, and v7, NanoID, and CUID2 — what each format is, how collision probability works, and when to use which for database primary keys, URLs, and distributed systems.

UUIDNanoIDCUIDdatabasedistributed systemsidentifiers

Every database record, API resource, distributed event, and session token needs a unique identifier. The choice of ID format matters more than it might seem — it affects security, database performance, URL readability, and how well your system behaves when you eventually run multiple servers or merge data from different sources. This guide covers the main options: UUIDs (v1, v4, v7), NanoIDs, and CUIDs, and when to reach for each one.

You can generate UUIDs and other unique IDs instantly with the BrowseryTools UUID Generator — free, no sign-up, everything generated locally in your browser.

Why Auto-Increment IDs Fall Short

Sequential integer IDs (1, 2, 3, ...) are the default in most relational databases, and they work well for simple single-server applications. But they create problems at scale or in distributed systems:

  • Predictability — anyone who knows one ID can guess others. /orders/1042 makes it obvious that order 1041 exists and that your business is not large. This is an IDOR (Insecure Direct Object Reference) vulnerability if you do not enforce authorization at the application layer.
  • Merge conflicts — when you need to combine data from two databases, two separate auto-increment sequences will have colliding IDs. Multi-tenant systems, offline-first apps, and migrations all hit this problem.
  • Distributed generation — if multiple servers or workers are inserting records, you need a coordination mechanism (a single sequence, or a database-level sequence) to avoid duplicate IDs. This creates a bottleneck.
  • Leaking business metrics — sequential IDs leak order volume, user count, and growth rate to competitors or researchers watching public IDs over time.

What Is a UUID?

A UUID (Universally Unique Identifier, also called a GUID) is a 128-bit number, conventionally displayed as 32 hexadecimal digits in five hyphen-separated groups:

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

Example: 550e8400-e29b-41d4-a716-446655440000
          ^        ^    ^    ^    ^
          |        |    |    |    12 hex digits (48 bits)
          |        |    |    variant bits (N)
          |        |    version digit (M)
          |        4 hex digits
          8 hex digits

The version digit (M) tells you which UUID generation algorithm was used. The variant bits (N) are always 8, 9, a, or b in standard UUIDs. The remaining 122 bits are available for actual identifier data.

UUID v1: MAC Address + Timestamp

UUID v1 combines the current timestamp (in 100-nanosecond intervals since October 15, 1582) with the MAC address of the generating machine and a clock sequence to handle rapid generation. The result is theoretically unique across all machines and time.

The problem is that v1 UUIDs reveal both when and where they were generated — the MAC address is embedded in plain sight. This is a privacy concern, and it was exploited in the Melissa worm (1999) to trace infected documents back to specific machines. For this reason, v1 is rarely used in new applications. Most developers who want time-ordered IDs reach for v7 instead.

UUID v4: Random

UUID v4 is the most widely used variant. It is 122 bits of cryptographically random data (the remaining 6 bits encode the version and variant). There is no timestamp, no MAC address, no sequential component — just entropy.

// Node.js 14.17+
const { randomUUID } = require('crypto');
randomUUID(); // → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"

// Browser
crypto.randomUUID(); // → "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed"

// Python
import uuid
str(uuid.uuid4()) # → "3d6f4580-2b3e-44e4-9d40-2d0ab12b4e7e"

How Unlikely Are UUID v4 Collisions?

With 122 bits of randomness, the probability of a collision is extraordinarily small. To have a 50% probability of at least one collision, you would need to generate approximately 2.7 × 1018 UUIDs — that is 2.7 quintillion. If you generated one billion UUIDs per second, it would take about 85 years to reach that threshold. For any real application, collisions are not a practical concern. The far more likely source of duplicate IDs is application bugs (copy-paste errors, cache hits returning old IDs, etc.), not the generator itself.

UUID v7: Time-Ordered Random

UUID v7 was standardized in RFC 9562 (2024) to address the main practical drawback of v4: random UUIDs make terrible database primary keys because they destroy index locality. When records are inserted with random IDs, each insert lands in a random position in a B-tree index, causing page splits, cache misses, and fragmentation at scale.

UUID v7 embeds a millisecond-precision Unix timestamp in the most significant bits, followed by random data. This means v7 UUIDs are sortable — records inserted chronologically have lexicographically increasing IDs — while still being globally unique and unpredictable beyond the millisecond boundary:

UUID v7 structure:
[48 bits: Unix ms timestamp][4 bits: version=7][12 bits: random][2 bits: variant][62 bits: random]

Three v7 UUIDs generated in sequence:
  0192fe2c-4b3a-7000-8000-0a1b2c3d4e5f  ← earliest
  0192fe2c-4b3b-7001-8000-0a1b2c3d4e60  ← slightly later
  0192fe2c-4b3c-7002-8000-0a1b2c3d4e61  ← latest
  ^^^^^^^^^^ timestamp prefix increases monotonically

If you are building a new application that uses UUIDs as primary keys in a relational database, v7 is the right default in 2024 and beyond.

NanoID: Shorter, URL-Safe

NanoID is not a UUID — it is a different ID format entirely, but it solves the same problem. By default it generates a 21-character string using an alphabet of URL-safe characters (A-Za-z0-9_-). This gives 126 bits of entropy — comparable to UUID v4 — in a string that is 21 characters instead of 36. NanoID strings are URL-friendly without encoding and look cleaner in logs and user-facing URLs:

UUID v4:  9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d  (36 chars)
NanoID:   V1StGXR8_Z5jdHi6B-myT                  (21 chars)

import { nanoid } from 'nanoid';
nanoid();      // → "V1StGXR8_Z5jdHi6B-myT"
nanoid(10);    // → "IRFa-VaY2b"  (custom length)

NanoID is popular for short link IDs, session tokens, invite codes, and any use case where the ID appears in a URL and you want it to be compact.

CUID2: Sortable, Fingerprint-Free

CUID2 (the successor to CUID) is designed specifically for use as database primary keys. It generates a 24-character string that is sortable by creation time, uses no MAC address or fingerprint, and is harder to predict than timestamp-based IDs. CUID2 uses SHA-3 internally to mix the timestamp with random data, making the output unpredictable even when generated at the same millisecond.

CUID2 is a good choice when you want sortable IDs, want to avoid the UUID format entirely, and care about the ID being opaque (not leaking timestamp information directly).

Choosing the Right Format

  • Database primary key, new project — UUID v7 or CUID2. Both are sortable, which keeps index performance healthy as data grows.
  • General-purpose unique ID, interoperability — UUID v4. Every language and framework understands the UUID format natively.
  • Short links, invite codes, URL tokens — NanoID. Compact, URL-safe, configurable length.
  • Distributed systems where IDs are generated client-side — UUID v4 or v7. No coordination needed; clients generate their own IDs before committing to the server.
  • Avoid v1 — it leaks your MAC address. No new project should use it.

Performance of UUID as a Primary Key

The classic warning about "don't use UUIDs as primary keys" is specifically about random UUIDs (v4) in MySQL with InnoDB or in any database that clusters data by primary key. Random insertion order fragments the clustered index. In PostgreSQL with a non-clustered UUID index, the penalty is less severe but still real at large scale. The practical solution: use UUID v7 or CUID2 (which are monotonically increasing) and the fragmentation problem largely disappears. Use the BrowseryTools UUID Generator to generate v7 UUIDs for testing your schema before committing to a format.

Free UUID Generator — v1, v4, v7, NanoID, CUID2

Open UUID Generator →

🛠️

Try the Tools — 100% Free, No Sign-Up

Everything runs in your browser. No uploads. No accounts. No ads.

Explore All Tools →