Saltar al contenido principal

UUID vs NanoID

Both generate identifiers that stay unique without a central authority. UUIDs are the standard: 36 characters, RFC 9562, built into every runtime and database. NanoIDs are the compact alternative — 21 URL-safe characters carrying comparable entropy. Default to UUIDs for keys and infrastructure; reach for NanoID when the ID appears in URLs.

Solo local

La guía de abajo solo está disponible en inglés.

UUID vs NanoID explained

Every distributed system needs identifiers two machines can create at the same moment without asking each other. UUIDs solved this in the 1980s, standardised as RFC 4122 and revised in 2024 as RFC 9562; NanoID arrived in 2017 as a minimal library chasing shorter strings. Both are collision-proof by the same mathematics — plenty of random bits — and neither needs a coordination server.

A UUID is 128 bits rendered as 36 characters: 32 hex digits in the 8-4-4-4-12 pattern, six of them spent on version and variant markers, so version 4 carries 122 random bits. A default NanoID is 21 characters drawn from A-Za-z0-9_- — 64 symbols of 6 bits each, 126 random bits, via crypto.getRandomValues. Different shapes, one collision plateau.

The real differences are operational: who can produce and validate each shape, how the IDs behave inside database indexes, how they look in a URL, and how reversible the choice is — all measured below, with a local generator linked throughout for comparing real output.

Want to see both shapes in real output? The UUID generator runs entirely in your browser — crypto.getRandomValues, no network calls, nothing logged.

For the full tour of what each version encodes, the UUID versions guide walks v1 through v8 with worked examples.

Anatomy: what is inside each ID

UUIDs encode their own metadata. Bits 48–51 hold the version — 1 for time-plus-MAC, 4 for random, 7 for time-ordered random — and two more bits fix the variant. A v4 always looks random; a v7 starts with a readable timestamp, because its first 48 bits are milliseconds since the Unix epoch and UUIDs minted on the same day share a prefix.

NanoIDs carry no metadata. Each character is an independent draw from the alphabet, chosen with masking and rejection sampling over crypto.getRandomValues so every symbol stays uniformly likely. That purity is why the format flexes — change the alphabet or length, keep the algorithm — and why a NanoID reveals nothing about when it was made.

AspectUUIDNanoID
Governing specRFC 9562 (2024, ex-RFC 4122)Library convention (nanoid) — no RFC
Default size36 characters, 128 bits21 characters, 126 bits
Alphabet0-9a-f plus 4 hyphensA-Za-z0-9_- (64 symbols)
Randomness sourceCSPRNG; crypto.randomUUID()crypto.getRandomValues with masking
Embedded timestampv1 and v7 yes; v4 noneNone — opaque by design
Useful entropy122 bits (v4); 74 random bits in v7126 bits at 21 characters

Collision maths: why neither one ever collides

The birthday bound says an n-bit random identifier reaches a 50 percent collision probability near 2^(n/2) draws. For UUID v4 that is roughly 2^61 — about 2.3 quintillion IDs — before a single duplicate's odds reach half; NanoID's 126 bits push the bar slightly further. In practice both are never-happens systems — any duplicate you meet is a code bug, not an entropy event.

This equivalence is why the size debate matters less than assumed: 21 NanoID characters are not safer than a v4 UUID — the same guarantee in fewer bytes. The honest reasons to choose are operational fit — storage, URLs, tooling — not collision risk.

Databases: the index-locality problem

Insert a random key into a B-tree index and the row can land on any page; fill pages partway in random order and every insert risks a page split, extra writes and a colder cache. That is the fragmentation tax both UUID v4 and NanoID pay — NanoID included, because it is just as random. On an indexed primary key at write-heavy scale, neither is index-friendly by default.

UUID v7 is the fix that ships inside the standard: its leading 48 bits are a millisecond timestamp, so new keys nearly always sort to the right edge of the index. NanoID cannot offer this: no time component, nothing to sort by. In an indexed column the real choice is v7 versus everything else.

  • v4 and NanoID scatter inserts across the tree — page splits and cache misses at scale.
  • Postgres' uuid type stores 16 raw bytes; a 36-character text key stores 37 or more.
  • NanoID's text edge — 21 characters against 36 — holds only while the alphabet stays documented.

URLs, alphabets and the length dial

NanoID's alphabet is URL-safe by construction: A-Za-z0-9_- need no percent-encoding anywhere in a URL, so an ID can be a path segment, query value or slug with zero escaping. UUIDs are technically URL-safe too — hex digits and hyphens never need encoding — but 36 characters is a lot of visible string for a link.

The custom alphabet is NanoID's most practical feature: numeric-only codes, lowercase short links — swap the 64 symbols, keep the algorithm. Respect the rule that entropy is length times log2 of alphabet size: an 8-character lowercase NanoID is about 38 bits, fine for a one-hour code, reckless as a primary key. UUIDs offer no such dial; the format is fixed at 128 bits.

When to pick which

Pick UUIDs when the ID lives in infrastructure: database primary keys (v7), interchange between teams and vendors, anything a third party must validate, anywhere a built-in beats a dependency. The standard is the product — every language, ORM and database already speaks it.

Pick NanoID when the ID is user-visible: short URLs, invitation links, file names, cookie values, request IDs in logs. The guidance reverses cleanly — if you keep fighting a UUID's width inside a URL, that link wants NanoID; if you find yourself reimplementing NanoID in a backend whose database could serve keys natively, that column wants a v7 UUID.

Frequently asked questions

Can I generate UUIDs or NanoIDs here without anything being sent to a server?

Yes. The generator runs in your tab using the browser's own crypto.getRandomValues, and no request leaves the page — the site's Content-Security-Policy blocks outbound calls. Open the DevTools Network panel while generating and watch it stay silent. Randomness comes from your OS via the browser, so quality matches server-side generation.

Are NanoIDs as collision-safe as UUID v4?

Slightly more so by raw bits: 126 versus v4's 122. The 50 percent collision point sits a little past 2^61 draws (about 2.3 quintillion IDs for v4), far beyond any realistic volume. The gap only becomes thinkable when you shrink NanoID's length or alphabet.

Should I use NanoID as a database primary key?

You can — but a 21-character text key is just as random as v4, so it inherits the same B-tree fragmentation on write-heavy tables. If inserts are hot, UUID v7 — time-ordered — is the index-friendly choice. NanoID buys shorter strings, not index locality.

Is NanoID a standard like UUID?

No. UUID is RFC 9562 with native support in every language, Postgres' uuid type and crypto.randomUUID(). NanoID is a library convention: small enough to reimplement in minutes, but every producer and consumer must agree on alphabet and length, and nothing validates conformance. That agreement is the price of 15 saved characters.

Why is UUID v7 recommended over v1?

v1's node field carries the machine's MAC address, which leaks hardware identity and links IDs across systems, and its 100-nanosecond Gregorian timestamp sorts awkwardly against Unix-time tooling. v7 replaces both with 48 bits of Unix milliseconds plus random bits: time-sortable, privacy-neutral, same RFC. Start new designs at v7 or v4.

How short can a NanoID be before collisions matter?

Entropy is characters times log2 of alphabet size; halve the exponent for the birthday bound. The default 21 characters is 126 bits. Twelve characters is 72 bits, about 2^36 draws to a coin-flip — fine per-user, thin for a global table. Eight is roughly 48 bits: short-lived codes, never primary keys.