NanoID Generator
Generate tiny URL-safe unique IDs with customizable alphabet
Alfabet
Grootte
Aantal
Klik op Genereren om NanoIDs te maken
Wat is NanoID?
NanoID is een kleine, snelle, URL-veilige willekeurige ID-generator. Standaard produceert het 21-teken strings met een 64-teken alfabet (A-Za-z0-9_-), wat ongeveer 126 bits entropie biedt — vergelijkbaar met UUID v4's 122 bits maar in een kortere string.
NanoID bevat geen tijdstempel of gestructureerde gegevens. Elke ID is puur willekeurig, gegenereerd uit de cryptografisch veilige willekeurige getallengenerator van het besturingssysteem (crypto.getRandomValues() in browsers, crypto.randomBytes() in Node.js).
NanoID vs UUID v4
NanoID en UUID v4 zijn beide willekeurige ID-generators ondersteund door een CSPRNG. Ze verschillen in formaat, lengte en ecosysteemondersteuning:
| Eigenschap | NanoID (standaard) | UUID v4 |
|---|---|---|
| Formaat | URL-veilig alfanumeriek + _- | Koppeltekens-hexadecimaal |
| Lengte | 21 tekens (standaard) | 36 tekens |
| Entropie | ~126 bits | 122 bits |
| URL-veilig | Ja — geen codering vereist | Ja (met koppeltekens) |
| Alfabet | 64 tekens (A-Za-z0-9_-) | 16 tekens (0-9a-f) |
| Afhankelijkheden | Vereist npm-pakket | Native (crypto.randomUUID) |
| Aanpasbaar | Ja — lengte en alfabet | Nee |
| Standaard | Geen (community-bibliotheek) | RFC 4122 / RFC 9562 |
Kies UUID v4 wanneer interoperabiliteit met externe systemen van belang is — databases met native UUID-kolommen, API's die UUID-formaat verwachten, of logging-infrastructuur die UUIDs parseert. Kies NanoID wanneer u kortere ID's wilt en de volledige stack beheert.
Botsingskans per grootte
NanoIDs botsingskans hangt af van de ID-lengte en de generatiesnelheid. De volgende tabel gebruikt het standaard 64-teken alfabet:
| Grootte (tekens) | Mogelijke ID's | Botsingsveiligheid |
|---|---|---|
| 6 | 64 | ~1 op 4,5 miljard — veilig voor een paar duizend ID's |
| 8 | 64 | ~1 op 4,5 biljoen — veilig voor miljoenen ID's |
| 11 | 64 | ~1 op 2,8 biljard — veilig voor miljarden ID's |
| 16 | 64 | ~1 op 1,2 × 10^19 — veilig voor biljoenen ID's |
| 21 | 64 | ~1 op 10^30 — veilig voor 100 miljard ID's per dag gedurende eeuwen |
| 32 | 64 | Vergelijkbaar met UUID v4 (122 bits) |
| 36 | 36 | Overtreft UUID v4 |
De standaard 21-teken grootte is gekozen om overeen te komen met UUID v4's botsingsbestendigheid (~126 bits) terwijl het 41% korter is. Voor de meeste toepassingen is 21 tekens de juiste keuze.
Aangepaste alfabetten
NanoIDs alfabet is volledig aanpasbaar. De bibliotheek accepteert elke string van unieke tekens als het alfabet en genereert ID's met alleen die tekens:
A-Za-z0-9_-A-Za-z0-90-9a-f0-9Belangrijk: gebruik nanoid/non-secure alleen voor niet-beveiligingsgevoelige toepassingen (bijv. UI-element-ID's). Voor elke ID die onraadbaar moet zijn, gebruik altijd de standaard veilige import.
Hoe NanoID willekeurigheid genereert
NanoID gebruikt de cryptografisch veilige pseudo-willekeurige getallengenerator (CSPRNG) van het besturingssysteem. In browsers is dat crypto.getRandomValues(); in Node.js is het crypto.randomFillSync(). Dit is dezelfde entropiebron die wordt gebruikt voor TLS-sessiesleutels — veel sterker dan Math.random().
Rejection-sampling (modulo-bias vermijden)
Een naïeve aanpak voor het genereren van willekeurige tekens zou zijn: neem een willekeurig byte (0–255) en bereken byte % alphabetSize. Dit introduceert modulo-bias — sommige tekens komen iets vaker voor dan andere wanneer de alfabetgrootte 256 niet gelijkmatig deelt.
NanoID elimineert deze bias met rejection-sampling:
- Bepaal het kleinste macht-van-twee-masker dat de alfabetgrootte dekt (bijv. voor een 64-teken alfabet is het masker 63 = 0b00111111)
- Genereer willekeurige bytes en pas het masker toe:
byte & mask - Als de gemaskeerde waarde binnen het alfabetbereik valt, gebruik die. Anders verwerpen en opnieuw proberen.
Dit betekent dat sommige willekeurige bytes worden verworpen, maar het resultaat is een perfect uniforme verdeling over het alfabet — geen teken is waarschijnlijker dan een ander.
// Pure browser — no npm package needed
function generateNanoid(alphabet, size) {
const mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1
const step = Math.ceil((1.6 * mask * size) / alphabet.length)
let id = ''
while (id.length < size) {
const bytes = crypto.getRandomValues(new Uint8Array(step))
for (const byte of bytes) {
const idx = byte & mask
if (idx < alphabet.length) {
id += alphabet[idx]
if (id.length === size) break
}
}
}
return id
}
const URL_SAFE = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'
generateNanoid(URL_SAFE, 21) // → "V1StGXR8_Z5jdHi6B-myT"Omgevingsondersteuning
Codevoorbeelden
JavaScript / TypeScript
// npm i nanoid
import { nanoid } from 'nanoid'
nanoid() // → "V1StGXR8_Z5jdHi6B-myT" (21 chars, URL-safe)
nanoid(8) // → "Uakgb_J5" (custom size)
// Custom alphabet
import { customAlphabet } from 'nanoid'
const hexId = customAlphabet('0123456789abcdef', 16)
hexId() // → "4f3a1b8c9d2e0f7a"
const numId = customAlphabet('0123456789', 8)
numId() // → "30812894"Browser (CDN)
NanoID kan direct in de browser worden gebruikt via een CDN-import. Geen build-stap vereist voor snel prototypen.
// Pure browser — no npm package needed
function generateNanoid(alphabet, size) {
const mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1
const step = Math.ceil((1.6 * mask * size) / alphabet.length)
let id = ''
while (id.length < size) {
const bytes = crypto.getRandomValues(new Uint8Array(step))
for (const byte of bytes) {
const idx = byte & mask
if (idx < alphabet.length) {
id += alphabet[idx]
if (id.length === size) break
}
}
}
return id
}
const URL_SAFE = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'
generateNanoid(URL_SAFE, 21) // → "V1StGXR8_Z5jdHi6B-myT"Python
# pip install nanoid
from nanoid import generate
generate() # → "V1StGXR8_Z5jdHi6B-myT"
generate(size=8) # → "Uakgb_J5"
generate('0123456789abcdef', 16) # custom alphabet + sizeNode.js (CommonJS)
// Node.js — stdlib only, no npm needed
const { randomFillSync } = require('crypto')
function nanoid(alphabet, size) {
const mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1
const step = Math.ceil((1.6 * mask * size) / alphabet.length)
let id = ''
while (id.length < size) {
const bytes = randomFillSync(Buffer.alloc(step))
for (const byte of bytes) {
const idx = byte & mask
if (idx < alphabet.length) { id += alphabet[idx]; if (id.length === size) break }
}
}
return id
}