เครื่องสร้าง NanoID
สร้าง ID ที่ไม่ซ้ำกันขนาดเล็กและปลอดภัยสำหรับ URL พร้อมตัวอักษรที่กำหนดเอง
ตัวอักษร
ขนาด
จำนวน
คลิกสร้างเพื่อสร้าง NanoID
NanoID คืออะไร?
NanoID คือ random ID generator ขนาดเล็ก เร็ว และ URL-safe ตามค่าเริ่มต้นสร้าง string 21 ตัวอักษรโดยใช้ alphabet 64 ตัวอักษร (A-Za-z0-9_-) ให้ entropy ประมาณ 126 บิต — เทียบเท่า UUID v4 122 บิตแต่ใน string ที่สั้นกว่า
NanoID ไม่ฝัง timestamp หรือข้อมูลที่มีโครงสร้างใดๆ ทุก ID เป็นสุ่มล้วน สร้างจาก cryptographically secure random number generator ของระบบปฏิบัติการ (crypto.getRandomValues() ในเบราว์เซอร์, crypto.randomBytes() ใน Node.js)
NanoID vs UUID v4
NanoID และ UUID v4 ทั้งคู่เป็น random ID generator ที่ใช้ CSPRNG แตกต่างกันในรูปแบบ ความยาว และการรองรับของระบบนิเวศ:
| คุณสมบัติ | NanoID (ค่าเริ่มต้น) | UUID v4 |
|---|---|---|
| Format | Alphanumeric URL-safe + _- | Hexadecimal พร้อมขีดกลาง |
| ความยาว | 21 ตัวอักษร (ค่าเริ่มต้น) | 36 ตัวอักษร |
| Entropy | ~126 บิต | 122 บิต |
| URL-safe | ใช่ — ไม่ต้องการการ encode | ใช่ (พร้อมขีดกลาง) |
| Alphabet | 64 ตัวอักษร (A-Za-z0-9_-) | 16 ตัวอักษร (0-9a-f) |
| Dependencies | ต้องการ npm package | Native (crypto.randomUUID) |
| ปรับแต่งได้ | ใช่ — ความยาวและ alphabet | ไม่ |
| มาตรฐาน | ไม่มี (community library) | RFC 4122 / RFC 9562 |
เลือก UUID v4 เมื่อความสามารถทำงานร่วมกับระบบภายนอกสำคัญ — ฐานข้อมูลที่มี UUID column แบบ native, API ที่คาดหวัง UUID format หรือโครงสร้างพื้นฐาน logging ที่ parse UUID เลือก NanoID เมื่อต้องการ ID ที่สั้นกว่าและควบคุม stack ทั้งหมด
ความน่าจะเป็นของ Collision ตามขนาด
ความน่าจะเป็น collision ของ NanoID ขึ้นอยู่กับความยาว ID และอัตราการสร้าง ตารางต่อไปนี้ใช้ alphabet 64 ตัวอักษรเริ่มต้น:
| ขนาด (ตัวอักษร) | ID ที่เป็นไปได้ | ความปลอดภัยจาก collision |
|---|---|---|
| 6 | 64 | ~1 ใน 4.5B — ปลอดภัยสำหรับ ID ไม่กี่พัน |
| 8 | 64 | ~1 ใน 4.5T — ปลอดภัยสำหรับ ID หลายล้าน |
| 11 | 64 | ~1 ใน 2.8 quadrillion — ปลอดภัยสำหรับ ID หลายพันล้าน |
| 16 | 64 | ~1 ใน 1.2 × 10^19 — ปลอดภัยสำหรับ ID หลายล้านล้าน |
| 21 | 64 | ~1 ใน 10^30 — ปลอดภัยสำหรับ 100 พันล้าน ID ต่อวันเป็นศตวรรษ |
| 32 | 64 | เทียบเท่า UUID v4 (122 บิต) |
| 36 | 36 | เกินกว่า UUID v4 |
ขนาดเริ่มต้น 21 ตัวอักษร ถูกเลือกให้ตรงกับการต้านทาน collision ของ UUID v4 (~126 บิต) ในขณะที่สั้นกว่า 41% สำหรับแอปพลิเคชันส่วนใหญ่ 21 ตัวอักษรเป็นตัวเลือกที่ถูกต้อง
Alphabet แบบกำหนดเอง
alphabet ของ NanoID ปรับแต่งได้อย่างสมบูรณ์ library รับ string ตัวอักษรที่ไม่ซ้ำใดก็ตามเป็น alphabet และสร้าง ID โดยใช้เฉพาะตัวอักษรเหล่านั้น:
A-Za-z0-9_-A-Za-z0-90-9a-f0-9สำคัญ: ใช้ nanoid/non-secure เฉพาะสำหรับแอปพลิเคชันที่ไม่ sensitive ด้านความปลอดภัย (เช่น UI element ID) สำหรับ ID ใดๆ ที่ต้องไม่สามารถเดาได้ ให้ใช้ default secure import เสมอ
NanoID สร้างความสุ่มอย่างไร
NanoID ใช้ cryptographically secure pseudo-random number generator (CSPRNG) ของระบบปฏิบัติการ ในเบราว์เซอร์คือ crypto.getRandomValues(); ใน Node.js คือ crypto.randomFillSync() นี่คือแหล่ง entropy เดิมที่ใช้สำหรับ TLS session key — แข็งแกร่งกว่า Math.random() อย่างมาก
Rejection Sampling (หลีกเลี่ยง Modulo Bias)
วิธีที่ไม่ซับซ้อนในการสร้างตัวอักษรสุ่มคือ: รับ byte สุ่ม (0–255) และคำนวณ byte % alphabetSize วิธีนี้ทำให้เกิด modulo bias — ตัวอักษรบางตัวปรากฏบ่อยกว่าตัวอื่นเล็กน้อยเมื่อขนาด alphabet ไม่หารลงตัวด้วย 256
NanoID กำจัด bias นี้โดยใช้ rejection sampling:
- กำหนด power-of-two mask ที่เล็กที่สุดที่ครอบคลุมขนาด alphabet (เช่น สำหรับ alphabet 64 ตัวอักษร mask คือ 63 = 0b00111111)
- สร้าง byte สุ่มและใช้ mask:
byte & mask - หากค่าที่ mask แล้วอยู่ในช่วง alphabet ให้ใช้ มิฉะนั้นทิ้งและลองใหม่
ซึ่งหมายความว่า byte สุ่มบางตัวถูก ทิ้ง แต่ผลลัพธ์คือการกระจายที่สม่ำเสมอสมบูรณ์แบบบน alphabet — ไม่มีตัวอักษรใดที่น่าจะเป็นมากกว่าตัวอื่น
// 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"การรองรับสภาพแวดล้อม
ตัวอย่างโค้ด
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 สามารถใช้โดยตรงในเบราว์เซอร์ผ่าน CDN import ไม่ต้องมี build step สำหรับ prototype อย่างรวดเร็ว
// 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
}