Email me

Explainer · 6 min read

Filed under App development Rust

UUID vs NanoID: which ID should you use?

Short answer

Use UUIDv7 for database primary keys and NanoID for short public strings like URL slugs and share codes. A default NanoID is 21 characters to a UUID's 36, with 126 random bits to UUIDv4's 122, so collisions are equally a non-issue. But NanoID is fully random: in our 2-million-row SQLite test, NanoID keys took 17.4 seconds to insert, UUIDv4 21.6 seconds, and time-ordered UUIDv7 2.6 seconds.

Glowing bar chart titled UUID vs NanoID: 2 million inserts, SQLite, ID as text primary key, seconds, lower is faster: UUIDv4 (36 characters) 21.6 seconds, NanoID (21 characters) 17.4 seconds, UUIDv7 (36 characters) 2.6 seconds.
NanoID and UUIDv4 are both fully random, so both scatter inserts across the index. Time-ordered UUIDv7 appends to the end and finished about 7 times faster. Our benchmark, Oct 24 2026. Rendered by Tensorust with the Proof Engine from our benchmark.

Part of the article Pick a UUIDv7 library that keeps order: 10 tested, .NET fails 50%. This page answers one question from it in depth.

On this page · 10 sections
  1. Key facts
  2. How each one is built
  3. Collision calculator
  4. Our benchmark
  5. Which should you use?
  6. Common misconceptions
  7. Our take
  8. Related
  9. FAQ
  10. Sources

NanoID's win is length, not speed. Stored as text, it made the smallest table (133.5 MB vs 198 MB for UUID text). Stored as a native 16-byte uuid column, UUID is smaller still.

Key facts

What UUID (v4 / v7) NanoID (default) Source (checked Oct 24 2026)
Standard IETF RFC 9562 (May 2024) Library convention (npm nanoid, 2017) RFC 9562, ai/nanoid
Text length 36 characters (hex + hyphens) 21 characters same
Alphabet 0-9, a-f A-Z, a-z, 0-9, _, - (64 symbols) same
Random bits 122 (v4), 74 (v7) 126 same
Binary form 16 bytes, native uuid types none, stored as text same
Sortable by time v7 yes, v4 no no same
2M inserts, SQLite text key v4 21.6 s, v7 2.6 s 17.4 s our benchmark
Table size, rowid / WITHOUT ROWID 198.0 / 101.4 MB 133.5 / 66.6 MB our benchmark
npm downloads, Oct 16 to 22 2026 uuid 187.3M nanoid 178.2M npm API

Download the data (CSV): all six benchmark runs.

How each one is built

UUIDv4 is 128 bits: 122 random, plus 4 version bits and 2 variant bits, printed as xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx. UUIDv7 swaps the first 48 bits for a millisecond Unix timestamp, so new IDs sort after old ones (v7 vs v4 explained).

NanoID has no layout at all. It draws 21 random bytes from the platform's secure generator, keeps 6 bits of each and maps them to a 64-symbol alphabet: V1StGXR8_Z5jdHi6B-myT. Because 64 divides 256 evenly, there is no modulo bias. Andrey Sitnik's library also ships customAlphabet() for other alphabets and lengths, which uses a mask and rejects out-of-range bytes to stay unbiased.

Collision calculator

Change the length or alphabet to see how many IDs it takes to reach a 1% chance of any two matching (birthday bound). Nothing leaves your browser.

At the default 21 characters and 1,000 IDs an hour, a 1% chance takes about 149 billion years, the same figure as the Nano ID collision calculator by GitHub user zelark that the library's README links to. Cut it to 10 characters and the 1% point arrives after about 152 million IDs; 8 characters, about 2.4 million.

Our benchmark

We inserted 2 million IDs of each kind into a SQLite table with the ID as a text primary key, in 50,000-row transactions, twice: once as a normal rowid table (the key gets a separate index) and once WITHOUT ROWID (the table is the index). Python 3.12.10's sqlite3, journaling off, on a Windows 11 desktop. UUIDv7 came from our own RFC 9562 generator; NanoID from the same algorithm as the library.

Glowing bar chart titled Same 2 million IDs, database size in megabytes, ID stored as text: UUIDv4 rowid 198.0, UUIDv7 rowid 197.8, NanoID rowid 133.5, UUID without rowid 101.4, NanoID without rowid 66.6.
A rowid table stores each key twice (table and index), so short keys pay off double. WITHOUT ROWID halves everything. Our benchmark, Oct 24 2026.

What it shows:

  1. Order beats length. NanoID is 42% shorter than a UUID string yet took only about 20% less time than UUIDv4 and 6.7 times slower than UUIDv7. Random keys force the database to write into the middle of its B-tree; time-ordered keys append to the end. The same effect is bigger at scale, as our 5-million-row v4 vs v7 test showed.
  2. Length still saves disk. As text, NanoID used about a third less space. If your IDs live as strings anyway (JSON APIs, document stores, URLs), that is real.
  3. Binary beats both. Postgres stores a uuid in 16 bytes; a 21-character text value takes 22 (a 1-byte header plus the characters). Our UUIDv7 vs ULID page measured text vs bytes directly.

Which should you use?

  • Database primary key: UUIDv7 in a native uuid column. Sortable, standard, and Postgres 18 generates it with uuidv7().
  • Public short links, invite codes, file names: NanoID, or a custom alphabet without look-alike characters.
  • Both: a UUIDv7 key inside, a NanoID public_id column outside. Common in apps that do not want sequential or time-revealing IDs in URLs (UUIDv7 leaks its creation time; here is how to read it).

Common misconceptions

Glowing bar chart titled npm downloads, week of Oct 16 to 22 2026, millions: uuid 187.3, nanoid 178.2, @paralleldrive/cuid2 13.3, ulid 7.6, uuidv7 2.0.
Weekly npm downloads of the main ID libraries. Downloads count installs, including CI and transitive dependencies, not developer choices. Data: api.npmjs.org, Oct 24 2026.
Myth

"NanoID is basically as popular as UUID, so everyone is choosing it."

The recordThe record: nanoid had 178.2M weekly npm downloads to uuid's 187.3M, but much of that comes as a dependency: PostCSS, which nearly every front-end build uses, depends on nanoid. What is true: it is the most-installed ID library after uuid.

Myth

"Shorter IDs collide sooner, so NanoID is riskier."

The recordThe record: at its default length it has 4 more random bits than UUIDv4. What is true: shortened NanoIDs (8 to 12 characters) do collide at realistic volumes; check with the calculator above.

Myth

"NanoID is faster, so it makes the app faster."

The recordThe record: the library is faster at generating IDs than crypto.randomUUID() per its own benchmark, but generation takes nanoseconds; the database index is where the time goes, and there NanoID behaves like UUIDv4.

FAQ

What is the difference between UUID and NanoID?

A UUID is a 128-bit ID standardized in RFC 9562 and usually written as 36 hex characters with hyphens; version 4 has 122 random bits. NanoID is a string generator from the nanoid JavaScript library: by default 21 characters from a 64-symbol URL-safe alphabet (A-Z, a-z, 0-9, underscore and hyphen), which gives 126 random bits. NanoID has no version bits, no timestamp and no standard binary form.

Is NanoID more likely to collide than UUID?

No. A default 21-character NanoID has 126 random bits against UUIDv4's 122, so it is slightly less likely to collide. You would need about 1.3 quintillion NanoIDs (roughly 149 billion years at 1,000 IDs an hour) for a 1% chance of one collision.

Is NanoID good as a database primary key?

It works, but it is fully random, so inserts land all over the index. In our test on a 2-million-row SQLite table, NanoID keys took 17.4 seconds to insert against 2.6 seconds for time-ordered UUIDv7. If you want short public IDs, a common pattern is a UUIDv7 primary key plus a NanoID column for URLs.

Can I make NanoID shorter?

Yes, nanoid(10) gives 10 characters, but collision odds rise fast: 10 characters is 60 bits, and a 1% chance of a collision arrives after about 152 million IDs. Use the calculator on this page before shortening.

Is NanoID secure?

The default nanoid() uses the platform's cryptographically secure random generator, so IDs are unpredictable. The separate nanoid/non-secure export uses Math.random and should not be used where guessing an ID would expose data.

Sources

All checked October 24, 2026.

Specs and libraries

Data

Our data

  • data.csv: our benchmark, October 24, 2026. 2,000,000 IDs per run, inserted with executemany in 50,000-row transactions into CREATE TABLE t(id TEXT PRIMARY KEY, n INTEGER) with and without WITHOUT ROWID; Python 3.12.10 sqlite3, journal_mode=off, synchronous=off; one run each, Windows 11 desktop. UUIDv4 from Python's uuid.uuid4(); UUIDv7 from our own RFC 9562 generator (48-bit ms timestamp, 74 random bits); NanoID as 21 secure random bytes masked to 6 bits over A-Za-z0-9_-. Collision figures use the birthday bound n = sqrt(2 x ln(1/0.99) x alphabet^length) (our math).

Images

  • All three charts rendered by Tensorust with the Proof Engine from our benchmark and npm data.

Next question

Every number on this page links to its source and was checked on Oct 24, 2026. Spot an error or a newer figure? Email matt@tensorust.com and it gets fixed. Related: UUIDv7 generator and decoder, Snowflake ID decoder.

Read next

Back to The Manual →   All articles →

Get the next one by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Up next

The article this answer comes fromPick a UUIDv7 library that keeps order: 10 tested, .NET fails 50%We tested 10 UUIDv7 libraries with 1M IDs each and a clock jump. .NET put 50% out of order, uuid6 ran 16.6 min ahead. The 2 that passed, plus free data.Read it next →

Get the receipts by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Cite this

Free to cite and reuse under CC BY 4.0 with a link back. How it was collected: methods. Spotted an error? Corrections.

Did this answer your question?

Popular in the shop

All 124 tools →

Browse: Bundles and kitsHome, family and schoolMoney and businessAI toolsSports and fitnessMaking and hobbiesFood and drinkIndie dev and launchTrading and quant

Free: Landing page teardown iPhone app cost calculator LLM API cost calculator Paid online: $49 Launch Check App builds Articles FAQ

Disagree, or have a number to add? Discuss this on The Floor →