Nano ID vs UUID vs Auto-Increment IDs Compared
Every new table and every public URL needs an ID scheme. Here is how Nano ID, UUID and auto-increment compare, with the collision maths worked out and a tested Nano ID function.
Nano ID vs UUID vs a plain auto-increment number is a choice every new table and every public URL forces on you. The Nano ID Generator creates IDs in the browser, and its page explains how alphabet and length trade off. This guide compares the three schemes as a design decision.
Nano ID vs UUID vs auto-increment at a glance
Example Length Random bits
Auto-increment 48213 grows none
UUID v4 7e338c66-c54b-426e-b18a-030cb358d321 36 122
UUID v7 01a14e9b-ce01-7b63-b660-535fa2569f01 36 74, plus a timestamp
Nano ID 4YI8VTtMxq1wiWgdbvHkm 21 126A default Nano ID carries slightly more randomness than a UUID v4 in 21 characters instead of 36, because each character holds 6 bits from a 64-character alphabet of letters, digits, _ and -, all safe in URLs.
How likely is a collision?
For random IDs, the chance of any two being equal grows with the square of how many you create. Worked out for a one-in-a-million chance of a single collision:
ID Random bits IDs before a 1-in-a-million collision chance
UUID v4 122 about 3.3 quadrillion (3.3 x 10^15)
Nano ID, 21 126 about 13 quadrillion (1.3 x 10^16)
Nano ID, 10 60 about 1.5 million
Nano ID, 8 48 about 24,000Default lengths are safe for any realistic system. Short IDs are where the risk is: an 8-character ID reaches a one-in-a-million collision chance after about 24,000 IDs, which a busy table reaches in a day. If you shorten IDs, add a unique constraint and retry on conflict.
What each ID reveals in a URL
- Auto-increment tells anyone how many records exist and how fast they grow:
/orders/48213today and/orders/48913next week says you took about 700 orders. It also invites guessing neighbours, so every endpoint must check that the caller may see that record. - UUID v7 reveals when the record was created, to the millisecond, because the timestamp is part of the ID.
- UUID v4 and Nano ID reveal nothing. They are still not access control: check permissions on every request, whatever the ID looks like.
How they behave in a database
Auto-increment and UUID v7 values grow over time, so new rows land at the end of the primary key index. Fully random IDs such as UUID v4 and Nano ID land anywhere in the index, which spreads writes across many pages and makes the index larger on very large tables. A common compromise is an internal auto-increment or UUID v7 primary key, plus a random public ID in a separate unique column for URLs.
Generate a Nano ID without a library
const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-";
function nanoid(size = 21) {
const bytes = crypto.getRandomValues(new Uint8Array(size));
let id = "";
for (const byte of bytes) id += alphabet[byte & 63];
return id;
}byte & 63 keeps the lowest 6 bits of each random byte, which picks every character with equal probability because the alphabet has exactly 64 characters. That only works for an alphabet of exactly 64. Check the length if you change it: with 63 characters, one value in 64 would point past the end of the string. For other alphabet sizes, use the nanoid package, which handles the general case.
Related tools
Related guides
Every modern runtime can generate a UUID without a library. Here are the one-liners for JavaScript, Python and PostgreSQL, a tested UUID v7 function, and two common mistakes.
NIST's guidance dropped the rules most sign-up forms still enforce. Here is what it recommends instead, why length beats symbols in numbers, and how to generate passwords securely in code.
A published SHA-256 checksum only helps if you compare it. Here are the exact commands for each operating system, a one-step check against a checksum file, and code for Node.js and Python.