NanoID 생성기
Generate tiny URL-safe unique IDs with customizable alphabet
알파벳
크기
개수
생성 버튼을 클릭하여 NanoID를 만드세요
NanoID란 무엇인가요?
NanoID는 작고, 빠르고, URL 안전한 무작위 ID 생성기입니다. 기본적으로 64자 알파벳(A-Za-z0-9_-)을 사용하여 21자 문자열을 생성하고 약 126비트의 엔트로피를 제공합니다——UUID v4의 122비트에 필적하지만 더 짧은 문자열입니다.
NanoID는 타임스탬프나 구조화된 데이터를 내장하지 않습니다. 모든 ID는 운영 체제의 암호학적으로 안전한 난수 생성기(브라우저의 crypto.getRandomValues(), Node.js의 crypto.randomBytes())에서 생성된 순수 무작위입니다.
NanoID 대 UUID v4
NanoID와 UUID v4는 모두 CSPRNG로 지원되는 무작위 ID 생성기입니다. 형식, 길이, 생태계 지원이 다릅니다:
| 속성 | NanoID(기본값) | UUID v4 |
|---|---|---|
| 형식 | URL 안전 영숫자 + _- | 하이픈 16진 |
| 길이 | 21자(기본값) | 36자 |
| 엔트로피 | ~126비트 | 122비트 |
| URL 안전 | 예——인코딩 불필요 | 예(하이픈 포함) |
| 알파벳 | 64자(A-Za-z0-9_-) | 16자(0-9a-f) |
| 의존성 | npm 패키지 필요 | 네이티브(crypto.randomUUID) |
| 사용자 정의 가능 | 예——길이 및 알파벳 | 아니오 |
| 표준 | 없음(커뮤니티 라이브러리) | RFC 4122 / RFC 9562 |
외부 시스템과의 상호 운용성이 중요할 때——네이티브 UUID 열을 가진 데이터베이스, UUID 형식을 기대하는 API, UUID를 파싱하는 로깅 인프라——UUID v4를 선택하세요. 더 짧은 ID를 원하고 전체 스택을 제어할 때 NanoID를 선택하세요.
크기별 충돌 확률
NanoID의 충돌 확률은 ID 길이와 생성 속도에 따라 다릅니다. 다음 표는 기본 64자 알파벳을 사용합니다:
| 크기(자) | 가능한 ID 수 | 충돌 안전성 |
|---|---|---|
| 6 | 64 | 약 1/45억——수천 개의 ID에 안전 |
| 8 | 64 | 약 1/4.5조——수백만 개의 ID에 안전 |
| 11 | 64 | 약 1/2.8경——수십억 개의 ID에 안전 |
| 16 | 64 | 약 1/1.2 × 10^19——수조 개의 ID에 안전 |
| 21 | 64 | 약 1/10^30——수백 년 동안 하루 1000억 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는 거부 샘플링을 사용하여 이 편향을 제거합니다:
- 알파벳 크기를 커버하는 최소 2의 거듭제곱 마스크를 결정합니다(예: 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
}