Generator NanoID
Generuje małe, bezpieczne dla URL unikalne ID z konfigurowalnym alfabetem
Alfabet
Rozmiar
Liczba
Kliknij Generuj, aby utworzyć NanoID
Czym jest NanoID?
NanoID to mały, szybki, bezpieczny dla URL generator losowych identyfikatorów. Domyślnie produkuje 21-znakowe ciągi przy użyciu 64-znakowego alfabetu (A-Za-z0-9_-), zapewniając około 126 bitów entropii — porównywalnych do 122 bitów UUID v4, ale w krótszym ciągu.
NanoID nie osadza znacznika czasu ani żadnych danych strukturalnych. Każdy identyfikator jest czysto losowy, generowany z kryptograficznie bezpiecznego generatora liczb losowych systemu operacyjnego (crypto.getRandomValues() w przeglądarkach, crypto.randomBytes() w Node.js).
NanoID a UUID v4
NanoID i UUID v4 to generatory losowych identyfikatorów obsługiwane przez CSPRNG. Różnią się formatem, długością i obsługą przez ekosystem:
| Właściwość | NanoID (domyślnie) | UUID v4 |
|---|---|---|
| Format | Alfanumeryczny bezpieczny dla URL + _- | Szesnastkowy z myślnikami |
| Długość | 21 znaków (domyślnie) | 36 znaków |
| Entropia | ~126 bitów | 122 bity |
| Bezpieczny dla URL | Tak — nie wymagane kodowanie | Tak (z myślnikami) |
| Alfabet | 64 znaki (A-Za-z0-9_-) | 16 znaków (0-9a-f) |
| Zależności | Wymaga pakietu npm | Natywny (crypto.randomUUID) |
| Konfigurowalny | Tak — długość i alfabet | Nie |
| Standard | Brak (biblioteka społecznościowa) | RFC 4122 / RFC 9562 |
Wybierz UUID v4, gdy liczy się interoperacyjność z systemami zewnętrznymi — bazy danych z natywnymi kolumnami UUID, API oczekujące formatu UUID lub infrastruktura logowania parsująca UUID. Wybierz NanoID, gdy chcesz krótszych identyfikatorów i kontrolujesz cały stos.
Prawdopodobieństwo kolizji według rozmiaru
Prawdopodobieństwo kolizji NanoID zależy od długości identyfikatora i tempa generowania. Poniższa tabela używa domyślnego 64-znakowego alfabetu:
| Rozmiar (znaki) | Możliwe identyfikatory | Bezpieczeństwo kolizji |
|---|---|---|
| 6 | 64 | ~1 na 4,5 mld — bezpieczne dla kilku tysięcy identyfikatorów |
| 8 | 64 | ~1 na 4,5 bln — bezpieczne dla milionów identyfikatorów |
| 11 | 64 | ~1 na 2,8 biliarda — bezpieczne dla miliardów identyfikatorów |
| 16 | 64 | ~1 na 1,2 × 10^19 — bezpieczne dla bilionów identyfikatorów |
| 21 | 64 | ~1 na 10^30 — bezpieczne dla 100 miliardów identyfikatorów dziennie przez wieki |
| 32 | 64 | Porównywalny do UUID v4 (122 bity) |
| 36 | 36 | Przekracza UUID v4 |
Domyślny rozmiar 21 znaków jest wybrany tak, aby odpowiadać odporności UUID v4 na kolizje (~126 bitów), będąc przy tym o 41% krótszy. Dla większości aplikacji 21 znaków to właściwy wybór.
Niestandardowe alfabety
Alfabet NanoID jest w pełni konfigurowalny. Biblioteka akceptuje dowolny ciąg unikalnych znaków jako alfabet i generuje identyfikatory używając wyłącznie tych znaków:
A-Za-z0-9_-A-Za-z0-90-9a-f0-9Ważne: używaj nanoid/non-secure tylko dla aplikacji niewrażliwych na bezpieczeństwo (np. identyfikatory elementów UI). Dla każdego identyfikatora, który musi być nieodgadniony, zawsze używaj domyślnego bezpiecznego importu.
Jak NanoID generuje losowość
NanoID używa kryptograficznie bezpiecznego pseudolosowego generatora liczb (CSPRNG) systemu operacyjnego. W przeglądarkach to crypto.getRandomValues(); w Node.js to crypto.randomFillSync(). To to samo źródło entropii co dla kluczy sesji TLS — znacznie silniejsze niż Math.random().
Odrzucanie próbek (unikanie obciążenia modulo)
Naiwnym podejściem do generowania losowych znaków byłoby: weź losowy bajt (0–255) i oblicz byte % alphabetSize. Wprowadza to obciążenie modulo — niektóre znaki pojawiają się nieco częściej niż inne, gdy rozmiar alfabetu nie dzieli równo 256.
NanoID eliminuje to obciążenie przy użyciu odrzucania próbek:
- Wyznacz najmniejszą maskę potęgi dwójki pokrywającą rozmiar alfabetu (np. dla 64-znakowego alfabetu maska to 63 = 0b00111111)
- Generuj losowe bajty i zastosuj maskę:
byte & mask - Jeśli zamaskowana wartość mieści się w zakresie alfabetu, użyj jej. W przeciwnym razie odrzuć i spróbuj ponownie.
Oznacza to, że niektóre losowe bajty są odrzucane, ale wynikiem jest perfekcyjnie równomierny rozkład po alfabecie — żaden znak nie jest bardziej prawdopodobny niż inny.
// 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"Obsługa środowisk
Przykłady kodu
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"Przeglądarka (CDN)
NanoID może być używany bezpośrednio w przeglądarce poprzez import CDN. Nie wymagany krok budowania dla szybkiego prototypowania.
// 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
}