NanoID কী?
NanoID একটি ছোট, দ্রুত, URL-নিরাপদ র্যান্ডম ID জেনারেটর। ডিফল্টভাবে এটি একটি 64-অক্ষরের অ্যালফাবেট (A-Za-z0-9_-) ব্যবহার করে 21-অক্ষরের স্ট্রিং তৈরি করে, যা প্রায় 126 বিট এন্ট্রপি প্রদান করে — UUID v4-এর 122 বিটের তুলনীয় কিন্তু একটি ছোট স্ট্রিংয়ে।
NanoID কোনো টাইমস্ট্যাম্প বা কাঠামোগত ডেটা সংযুক্ত করে না। প্রতিটি ID সম্পূর্ণ র্যান্ডম, অপারেটিং সিস্টেমের ক্রিপ্টোগ্রাফিক্যালি নিরাপদ র্যান্ডম নম্বর জেনারেটর (crypto.getRandomValues() ব্রাউজারে, crypto.randomBytes() Node.js-এ) থেকে তৈরি।
NanoID বনাম UUID v4
NanoID এবং UUID v4 উভয়ই CSPRNG-নির্ভর র্যান্ডম ID জেনারেটর। এগুলোর মধ্যে ফর্ম্যাট, দৈর্ঘ্য এবং ইকোসিস্টেম সাপোর্টে পার্থক্য রয়েছে:
| বৈশিষ্ট্য | NanoID (ডিফল্ট) | UUID v4 |
|---|---|---|
| ফর্ম্যাট | URL-নিরাপদ আলফানিউমেরিক + _- | হাইফেনযুক্ত হেক্সাডেসিমাল |
| দৈর্ঘ্য | 21 অক্ষর (ডিফল্ট) | 36 অক্ষর |
| এন্ট্রপি | ~126 বিট | 122 বিট |
| URL-নিরাপদ | হ্যাঁ — কোনো এনকোডিং প্রয়োজন নেই | হ্যাঁ (হাইফেনসহ) |
| অ্যালফাবেট | 64 অক্ষর (A-Za-z0-9_-) | 16 অক্ষর (0-9a-f) |
| নির্ভরতা | npm প্যাকেজ প্রয়োজন | নেটিভ (crypto.randomUUID) |
| কাস্টমাইজযোগ্য | হ্যাঁ — দৈর্ঘ্য ও অ্যালফাবেট | না |
| মানক | কোনো মানক নেই (কমিউনিটি লাইব্রেরি) | RFC 4122 / RFC 9562 |
বাহ্যিক সিস্টেমের সাথে ইন্টারঅপারেবিলিটি গুরুত্বপূর্ণ হলে UUID v4 বেছে নিন — নেটিভ UUID কলাম সহ ডেটাবেজ, UUID ফর্ম্যাট প্রত্যাশা করা API, বা UUID পার্স করা লগিং অবকাঠামো। ছোট ID চাইলে এবং পুরো স্ট্যাক নিজে নিয়ন্ত্রণ করলে NanoID বেছে নিন।
সাইজ অনুযায়ী কলিশন সম্ভাব্যতা
NanoID-এর কলিশন সম্ভাব্যতা ID-এর দৈর্ঘ্য ও তৈরির হারের উপর নির্ভর করে। নিচের টেবিলে ডিফল্ট 64-অক্ষরের অ্যালফাবেট ব্যবহার করা হয়েছে:
| সাইজ (অক্ষর) | সম্ভাব্য ID সংখ্যা | কলিশন নিরাপত্তা |
|---|---|---|
| 6 | 64 | ~৪.৫ বিলিয়নে ১ — কয়েক হাজার ID-এর জন্য নিরাপদ |
| 8 | 64 | ~৪.৫ ট্রিলিয়নে ১ — লক্ষাধিক ID-এর জন্য নিরাপদ |
| 11 | 64 | ~২.৮ কোয়াড্রিলিয়নে ১ — কোটি কোটি ID-এর জন্য নিরাপদ |
| 16 | 64 | ~১.২ × 10^19-এ ১ — ট্রিলিয়ন ID-এর জন্য নিরাপদ |
| 21 | 64 | ~10^30-এ ১ — শতাব্দীর পর শতাব্দী দৈনিক ১০০ বিলিয়ন ID-এর জন্য নিরাপদ |
| 32 | 64 | UUID v4 (122 বিট)-এর সমতুল্য |
| 36 | 36 | UUID v4 ছাড়িয়ে যায় |
ডিফল্ট 21-অক্ষরের সাইজ UUID v4-এর কলিশন প্রতিরোধ (~126 বিট) বজায় রেখে 41% ছোট হওয়ার জন্য বেছে নেওয়া হয়েছে। বেশিরভাগ অ্যাপ্লিকেশনের জন্য 21 অক্ষর সঠিক পছন্দ।
কাস্টম অ্যালফাবেট
NanoID-এর অ্যালফাবেট সম্পূর্ণরূপে কাস্টমাইজযোগ্য। লাইব্রেরিটি যেকোনো অনন্য অক্ষরের স্ট্রিং অ্যালফাবেট হিসেবে গ্রহণ করে এবং শুধুমাত্র সেই অক্ষরগুলো ব্যবহার করে ID তৈরি করে:
A-Za-z0-9_-A-Za-z0-90-9a-f0-9গুরুত্বপূর্ণ: nanoid/non-secure শুধুমাত্র নিরাপত্তা-অসংবেদনশীল অ্যাপ্লিকেশনে ব্যবহার করুন (যেমন UI এলিমেন্ট ID)। যেকোনো ID যা অনুমান করা যাবে না তার জন্য সবসময় ডিফল্ট নিরাপদ ইম্পোর্ট ব্যবহার করুন।
NanoID কীভাবে র্যান্ডমনেস তৈরি করে
NanoID অপারেটিং সিস্টেমের ক্রিপ্টোগ্রাফিক্যালি নিরাপদ সিউডো-র্যান্ডম নম্বর জেনারেটর (CSPRNG) ব্যবহার করে। ব্রাউজারে এটি crypto.getRandomValues(); Node.js-এ এটি crypto.randomFillSync()। এটি TLS সেশন কী-এর জন্য ব্যবহৃত একই এন্ট্রপি উৎস — Math.random()-এর চেয়ে অনেক বেশি শক্তিশালী।
রিজেকশন স্যাম্পলিং (মডুলো বায়াস এড়ানো)
র্যান্ডম অক্ষর তৈরির একটি সাধারণ পদ্ধতি হল: একটি র্যান্ডম বাইট (0–255) নিয়ে byte % alphabetSize গণনা করা। যখন অ্যালফাবেটের সাইজ 256-কে সমানভাবে বিভাজন করে না, তখন এটি মডুলো বায়াস তৈরি করে — কিছু অক্ষর অন্যদের চেয়ে সামান্য বেশি দেখা যায়।
NanoID রিজেকশন স্যাম্পলিং ব্যবহার করে এই বায়াস দূর করে:
- অ্যালফাবেট সাইজ কভার করার জন্য সবচেয়ে ছোট দুইয়ের পাওয়ার মাস্ক নির্ধারণ করুন (যেমন 64-অক্ষরের অ্যালফাবেটের জন্য মাস্ক হবে 63 = 0b00111111)
- র্যান্ডম বাইট তৈরি করুন এবং মাস্ক প্রয়োগ করুন:
byte & mask - মাস্ক করা মান অ্যালফাবেটের সীমার মধ্যে থাকলে ব্যবহার করুন। অন্যথায় বাতিল করুন এবং আবার চেষ্টা করুন।
এর মানে কিছু র্যান্ডম বাইট বাতিল হয়, কিন্তু ফলাফল হয় অ্যালফাবেটের উপর সম্পূর্ণ সমান বিতরণ — কোনো অক্ষরই অন্যটির চেয়ে বেশি সম্ভাব্য নয়।
// 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"ব্রাউজার (CDN)
NanoID CDN ইম্পোর্টের মাধ্যমে সরাসরি ব্রাউজারে ব্যবহার করা যায়। দ্রুত প্রোটোটাইপিংয়ের জন্য কোনো বিল্ড ধাপের প্রয়োজন নেই।
// 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
}