JavaScript UUID v4 생성하기 온라인

·TypeScript & Full-stack Developer·검토자Marcus Webb·게시일

무료 UUID v4 생성기을 브라우저에서 직접 사용하세요 — 설치 불필요.

UUID v4 생성기 온라인으로 사용하기 →

모든 JavaScript 애플리케이션은 결국 고유 식별자가 필요합니다 — 세션 토큰, 데이터베이스 행, 결제 API의 멱등성 키, 분산 추적을 위한 상관관계 ID. 오늘날 JavaScript에서 UUID v4를 생성하는 가장 간단한 방법은 crypto.randomUUID()입니다: 의존성 없이, 한 줄로, 암호학적으로 안전합니다. UUID v4는 서비스 간 조율 없이도 클라이언트와 서버 모두 독립적으로 ID를 생성할 수 있어 충돌 위험이 없기 때문에 널리 사용됩니다. 이 가이드는 해당 내장 API와 uuid npm 패키지, 유효성 검사를 모두 다룹니다 — Node.js 19+ 및 모던 브라우저 기준. 코드 없이 사용하고 싶다면 ToolDeck의 UUID v4 생성기 즉시 규격에 맞는 식별자를 생성해 줍니다.

  • crypto.randomUUID()는 브라우저와 Node.js에 내장되어 있습니다 — 의존성 없이 한 줄로 사용 가능합니다.
  • UUID v4는 128비트 난수 식별자입니다: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx (y는 8, 9, a, 또는 b).
  • /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i 로 검증하세요 — 버전과 배리언트 비트를 확인합니다.
  • uuid npm 패키지는 랜덤 ID 이상이 필요할 때 v1, v3, v5, v7 지원을 추가합니다.
  • 데이터베이스 기본 키로는 인덱스 단편화를 줄이기 위해 v4(무작위) 대신 UUID v7(시간 순서)을 사용하세요.

UUID v4란 무엇인가요?

UUID(범용 고유 식별자) 버전 4는 32개의 16진수를 네 개의 하이픈으로 구분한 128비트 난수 식별자입니다: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx. 위치 15의 4는 버전을 나타냅니다. 위치 20의 y 문자는 8, 9, a, 또는 b 중 하나입니다 (RFC 4122 배리언트). 나머지 122비트는 난수입니다. UUID v4는 시스템 간 조율 없이 클라이언트와 서버에서 독립적으로 ID를 생성할 수 있어 JavaScript 애플리케이션에서 가장 일반적인 버전입니다.

Before · javascript
After · javascript
// 식별자 없음
const event = { action: "user.login", ts: 1711824000 };
// UUID v4 포함
const event = {
  id: "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
  action: "user.login",
  ts: 1711824000
};

crypto.randomUUID() — 네이티브 JavaScript 접근법

crypto.randomUUID() 는 Chrome 92+, Firefox 95+, Safari 15.4+, Node.js 19+(Node.js 14.17.0부터 globalThis.crypto로 실험적 지원)에서 사용 가능합니다. 소문자 36자 UUID v4 문자열을 반환합니다. 브라우저 JavaScript에서는 import가 필요 없습니다. Node.js에서는 전역 crypto 객체에서 직접 호출하거나 node:crypto 모듈에서 명시적으로 가져올 수 있습니다.

JavaScript — 브라우저 (import 불필요)
// 모던 브라우저에서 바로 작동 — 빌드 단계나 번들러 불필요
const requestId = crypto.randomUUID();
console.log(requestId);
// "3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"

// 고유 식별자가 필요한 곳 어디에서나 사용
const telemetryEvent = {
  event_id: crypto.randomUUID(),
  action: "checkout.started",
  session_id: crypto.randomUUID(),
  timestamp: Date.now(),
  cart_total_cents: 14999,
};
console.log(JSON.stringify(telemetryEvent, null, 2));
Node.js — 두 가지 동등한 방법
// 방법 1: 전역 crypto (Node.js 19+)
const orderId = crypto.randomUUID();
console.log(orderId);
// "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"

// 방법 2: node:crypto에서 명시적 import
import { randomUUID } from 'node:crypto';
const correlationId = randomUUID();
console.log(correlationId);
// "f7e6d5c4-b3a2-4190-8f7e-6d5c4b3a2190"

코드가 오래된 브라우저나 임베디드 WebView에서 실행될 수 있다면 crypto.randomUUID 기능 탐지를 수행하는 것이 좋습니다. 단일 typeof 검사로 확인할 수 있습니다:

JavaScript — 폴백이 있는 기능 탐지
function generateUUIDv4() {
  // 네이티브 API가 있으면 우선 사용
  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
    return crypto.randomUUID();
  }

  // getRandomValues를 사용한 수동 폴백 (다음 섹션 참조)
  const bytes = new Uint8Array(16);
  crypto.getRandomValues(bytes);

  // 버전 (4)과 배리언트 (RFC 4122) 설정
  bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
  bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10xx

  const hex = [...bytes].map(b => b.toString(16).padStart(2, '0'));
  return [
    hex.slice(0, 4).join(''),
    hex.slice(4, 6).join(''),
    hex.slice(6, 8).join(''),
    hex.slice(8, 10).join(''),
    hex.slice(10, 16).join(''),
  ].join('-');
}

console.log(generateUUIDv4());
// "9b2e4f1a-7c3d-4e8f-a5b6-0d2c1e9f8a7b"
참고:보안 컨텍스트(HTTPS 페이지, localhost, 브라우저 확장)에서는 crypto.randomUUID()가 항상 사용 가능합니다. 일부 브라우저에서는 비보안 HTTP 페이지에서 오류가 발생합니다. 개발 중에 일반 HTTP에서 애플리케이션을 실행해야 한다면 위의 getRandomValues 폴백이 해당 경우를 처리합니다.

라이브러리 없이 UUID v4 생성하기

때로는 crypto.randomUUID()에 의존할 수 없는 경우가 있습니다 — crypto API를 제거한 WebView를 대상으로 하거나 내부 동작을 이해하고 싶을 때입니다. 수동 방식은 crypto.getRandomValues() (IE 11부터 사용 가능)를 사용하여 16바이트를 난수로 채운 다음, 두 번의 비트마스크 연산으로 버전과 배리언트 필드를 설정합니다. 이 두 연산이 UUID v4와 순수 난수 바이트 문자열의 유일한 차이점입니다.

JavaScript — getRandomValues를 사용한 수동 UUID v4
function uuidv4Manual() {
  const bytes = new Uint8Array(16);
  crypto.getRandomValues(bytes);

  // 버전 설정: 바이트 6의 비트 12–15 = 0100 (버전 4)
  bytes[6] = (bytes[6] & 0x0f) | 0x40;

  // 배리언트 설정: 바이트 8의 비트 6–7 = 10 (RFC 4122)
  bytes[8] = (bytes[8] & 0x3f) | 0x80;

  const hex = [...bytes].map(b => b.toString(16).padStart(2, '0'));

  return (
    hex.slice(0, 4).join('') + '-' +
    hex.slice(4, 6).join('') + '-' +
    hex.slice(6, 8).join('') + '-' +
    hex.slice(8, 10).join('') + '-' +
    hex.slice(10, 16).join('')
  );
}

const traceId = uuidv4Manual();
console.log(traceId);
// "e4d7c2a1-3f9b-48e5-a612-9d8c7b6a5f4e"

// UUID v4 유효성 검사 통과 여부 확인
const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
console.log(UUID_V4_RE.test(traceId)); // true
경고:UUID 생성에 Math.random()을 절대 사용하지 마세요. 암호학적으로 안전하지 않고, 출력 주기가 너무 짧으며, 일부 엔진에서는 예측 가능한 시퀀스를 생성합니다. 항상 crypto.getRandomValues() 또는 crypto.randomUUID()를 사용하세요.

uuid npm 패키지 — 다중 버전 지원

npm의 uuid 패키지는 crypto.randomUUID()가 생기기 전부터 JavaScript의 대표적인 UUID 라이브러리였습니다. 세 가지 상황에서 여전히 유용합니다: v4 이외의 UUID 버전(v1, v3, v5, v7)이 필요한 경우, Node.js 14.17.0보다 오래된 런타임을 대상으로 하는 경우, 또는 validate parse 유틸리티 함수가 필요한 경우입니다. 모던 런타임에서 단순히 UUID v4만 필요하다면 네이티브 API로 충분하며 의존성을 추가할 필요가 없습니다.

bash — 설치
npm install uuid
JavaScript — v4 생성을 위한 uuid 패키지
import { v4 as uuidv4, validate, version } from 'uuid';

// UUID v4 생성
const paymentId = uuidv4();
console.log(paymentId);
// "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed"

// UUID 문자열 유효성 검사
console.log(validate(paymentId));    // true
console.log(validate("not-a-uuid")); // false

// UUID의 버전 감지
console.log(version(paymentId));     // 4

// 테스트 데이터베이스 시딩을 위한 배치 생성
const testAccounts = Array.from({ length: 5 }, () => ({
  account_id: uuidv4(),
  plan: "starter",
  created_at: new Date().toISOString(),
}));
console.log(testAccounts);
참고:uuid 패키지는 내부적으로 브라우저에서 crypto.getRandomValues()를, Node.js에서는 crypto.randomBytes()를 사용하므로 엔트로피 소스는 네이티브 API와 동일합니다. 차이점은 추가 유틸리티 함수와 다중 버전 지원뿐입니다.

코드를 전혀 작성하고 싶지 않다면 UUID v4 생성기를 사용해 보세요 — 클릭 한 번으로 RFC 4122 규격 v4 식별자를 브라우저에서 바로 생성합니다.

결정론적 UUID — 문자열로 UUID v5 생성하기

UUID v4는 정의상 무작위입니다 — 두 번 호출하면 항상 다른 결과가 나옵니다. 때로는 반대가 필요합니다: 동일한 입력 문자열이 항상 동일한 UUID를 생성해야 합니다. 이것이 UUID v5가 하는 일입니다. 네임스페이스 UUID와 입력 문자열을 SHA-1로 해시한 다음 결과를 UUID 형식으로 만듭니다. 동일한 네임스페이스 + 동일한 입력 = 동일한 출력, 항상, 모든 머신에서. URL, 이메일 주소, 또는 이미 리소스를 식별하는 문자열에서 안정적인 ID를 도출할 때 유용합니다.

JavaScript — 결정론적 ID를 위한 uuid v5
import { v5 as uuidv5 } from 'uuid';

// URL을 위한 내장 네임스페이스 (RFC 4122)
const URL_NAMESPACE = uuidv5.URL;
// "6ba7b811-9dad-11d1-80b4-00c04fd430c8"

// 동일한 URL은 항상 동일한 UUID를 생성
const pageId1 = uuidv5("https://api.warehouse.dev/products/sku-7291", URL_NAMESPACE);
const pageId2 = uuidv5("https://api.warehouse.dev/products/sku-7291", URL_NAMESPACE);
console.log(pageId1 === pageId2); // true
console.log(pageId1);
// "a6e4e1c0-7e23-5d3b-8f14-9c2a1b3d5e7f"

// 애플리케이션을 위한 커스텀 네임스페이스
const APP_NAMESPACE = "f47ac10b-58cc-4372-a567-0e02b2c3d479";
const tenantId = uuidv5("acme-corp", APP_NAMESPACE);
console.log(tenantId);
// "d4735e3a-265b-564e-8f32-7a1b2c3d4e5f"

참고로 UUID v3는 SHA-1 대신 MD5를 사용한다는 점만 다릅니다. 새 프로젝트에는 v5를 사용하세요. MD5는 알려진 충돌 취약점이 있으며, ID 생성에서는 크게 중요하지 않지만 둘 다 사용 가능할 때 SHA-1 대신 MD5를 선택할 이유가 없습니다.

crypto.randomUUID() 및 관련 API 레퍼런스

네이티브 crypto.randomUUID() 는 인수를 받지 않습니다 — 문자열만 반환합니다. 의존성 없이 RFC 4122 규격 식별자가 필요할 때 사용하세요. 형식화된 UUID 문자열 대신 원시 난수 바이트가 필요한 경우(예: 타입 배열 채우기나 키 도출) — crypto.getRandomValues()를 직접 사용하세요. UUID 작업에 중요한 관련 API는 아래에 정리되어 있습니다.

속성 / 메서드
반환 타입
설명
crypto.randomUUID()
string
소문자 16진수와 하이픈으로 구성된 36자리 UUID v4 문자열을 반환합니다
crypto.getRandomValues(arr)
TypedArray
타입 배열을 암호학적으로 안전한 난수로 채웁니다 — 직접 UUID를 생성할 때 사용하는 기본 빌딩 블록
URL.createObjectURL(blob)
string
고유한 blob URL을 생성합니다 (UUID가 아니지만 혼동되는 경우가 있음)

UUID v4 정규식 패턴 분석:

세그먼트
패턴
의미
[0-9a-f]{8}
xxxxxxxx
첫 8개의 16진수 — 32비트 난수
[0-9a-f]{4}
xxxx
다음 4개의 16진수 — 16비트 난수
4[0-9a-f]{3}
4xxx
버전 니블이 4로 고정되며 이후 12비트 난수
[89ab][0-9a-f]{3}
yxxx
배리언트 니블은 8, 9, a, b 중 하나 — 이후 12비트 난수
[0-9a-f]{12}
xxxxxxxxxxxx
마지막 12개의 16진수 — 48비트 난수

정규식으로 UUID v4 검증하기

문자열이 올바른 UUID v4인지 검증하는 것은 — 수신 API 요청 본문, URL 매개변수, 웹훅 페이로드 — 자주 필요합니다. 의존성 없이 v4만 검증하고 싶다면 직접 작성한 정규식이 올바른 선택입니다. 이미 uuid 패키지를 사용 중이라면 대신 validate() 내보내기를 사용하세요 — 모든 UUID 버전을 처리하며 커스텀 패턴 관리보다 오류가 적습니다. 정규식 /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i 는 버전 니블(반드시 4여야 함)과 배리언트 니블(반드시 8, 9, a, 또는 b여야 함)을 모두 확인합니다. 불리언 검사에는 RegExp.prototype.test()를, 주변 텍스트에서 UUID를 추출할 때는 .match()를 사용하세요.

JavaScript — UUID v4 유효성 검사 헬퍼
const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;

function isUUIDv4(str) {
  return UUID_V4_RE.test(str);
}

// 유효한 UUID v4
console.log(isUUIDv4("9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d")); // true

// UUID v1 — 버전 니블이 4가 아닌 1
console.log(isUUIDv4("550e8400-e29b-11d4-a716-446655440000")); // false

// UUID v7 — 버전 니블이 7
console.log(isUUIDv4("018e4a0c-5b3f-7d12-8a9b-0c1d2e3f4a5b")); // false

// 잘못된 형식
console.log(isUUIDv4("not-a-uuid"));           // false
console.log(isUUIDv4(""));                      // false
console.log(isUUIDv4("9b1deb4d3b7d4bad9bdd2b0d7b3dcb6d")); // false (하이픈 없음)

// 더 긴 문자열에서 UUID 추출
const logLine = 'Request req_id=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d failed with 503';
const match = logLine.match(/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i);
console.log(match?.[0]);
// "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"

파일과 API 응답에 UUID 생성 및 첨부하기

실제로 crypto.randomUUID()를 단독으로 호출하는 경우는 드뭅니다. 두 가지 패턴이 자주 등장합니다: 데이터베이스에 쓰기 전 레코드에 ID를 할당하는 것과, 서비스 간 요청을 로그에서 추적할 수 있도록 아웃바운드 API 요청에 상관관계 ID를 첨부하는 것입니다.

NDJSON 파일 읽기 → UUID 할당 → 다시 쓰기

Node.js — 파일에서 레코드에 UUID 할당
import { readFileSync, writeFileSync } from 'node:fs';
import { randomUUID } from 'node:crypto';

function assignIds(inputPath, outputPath) {
  const lines = readFileSync(inputPath, 'utf-8')
    .split('\n')
    .filter(line => line.trim());

  const records = lines.map(line => {
    try {
      const record = JSON.parse(line);
      if (!record.id) {
        record.id = randomUUID();
      }
      return JSON.stringify(record);
    } catch (err) {
      console.error(`잘못된 줄 건너뜀: ${err.message}`);
      return null;
    }
  }).filter(Boolean);

  writeFileSync(outputPath, records.join('\n') + '\n');
  console.log(`${records.length}개 레코드에 ID 할당 → ${outputPath}`);
}

assignIds('warehouse-products.ndjson', 'warehouse-products-with-ids.ndjson');
// 1284개 레코드에 ID 할당 → warehouse-products-with-ids.ndjson

아웃바운드 API 요청에 상관관계 ID 첨부

Node.js — 분산 추적을 위한 상관관계 ID
import { randomUUID } from 'node:crypto';

async function createShipment(orderPayload) {
  const correlationId = randomUUID();

  try {
    const response = await fetch('https://api.logistics.dev/v2/shipments', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Correlation-ID': correlationId,
        'X-Idempotency-Key': randomUUID(),
      },
      body: JSON.stringify(orderPayload),
    });

    if (!response.ok) {
      const errorBody = await response.text();
      throw new Error(`Shipment API returned ${response.status}: ${errorBody}`);
    }

    const result = await response.json();
    console.log(`배송 생성됨: ${result.shipment_id} (상관관계: ${correlationId})`);
    return result;
  } catch (err) {
    console.error(`[correlation:${correlationId}] 배송 실패: ${err.message}`);
    throw err;
  }
}

await createShipment({
  order_id: "ord_8a3f91bc",
  destination: { city: "서울", state: "서울특별시", zip: "04524" },
  items: [{ sku: "WH-7291", quantity: 2, weight_kg: 1.4 }],
});

커맨드라인에서 UUID 생성

스크립트가 항상 필요한 것은 아닙니다. Node.js는 커맨드라인에서 직접 UUID를 생성할 수 있으며, 쉘 스크립트, CI 파이프라인, 빠른 임시 테스트에 유용합니다. -e 플래그는 단일 표현식을 평가합니다.

bash — 커맨드라인에서 UUID 생성
# UUID 하나
node -e "console.log(crypto.randomUUID())"
# 3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f

# UUID 다섯 개 한 번에
node -e "for(let i=0;i<5;i++) console.log(crypto.randomUUID())"

# 생성 후 쉘 변수에 할당
export REQUEST_ID=$(node -e "process.stdout.write(crypto.randomUUID())")
echo "Request ID: $REQUEST_ID"

# npx uuid 사용 (전역 설치 또는 일회성 사용)
npx uuid v4
# 1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed
bash — 브라우저 콘솔에서 UUID 생성 (Node.js 불필요)
# 브라우저 개발자 도구 콘솔에서 입력:
crypto.randomUUID()
# "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
참고:CI 파이프라인에서 Node.js를 사용할 수 없을 때는 uuidgen이 macOS 및 대부분의 Linux 배포판에 사전 설치되어 있습니다. 모던 시스템에서는 기본적으로 UUID v4를 생성합니다.

고성능 대안 — nanoid

초당 수천 개의 ID를 생성하고 36자 UUID 형식이 필수 요건이 아니라면 nanoid를 고려하세요.uuid.v4()보다 2배 빠르고, 기본적으로 21자 URL 안전 ID를 생성하며, 최소화 후 약 1 KB입니다. 출력은 UUID가 아닙니다 — 커스텀 알파벳 ID이므로 RFC 4122 규격이 필요한 곳(데이터베이스 UUID 컬럼, UUID 형식을 검증하는 API, OpenTelemetry 추적 ID)에는 사용하지 마세요. 하지만 내부 상관관계 ID, React 컴포넌트 키, URL 슬러그에는 적합합니다.

bash — nanoid 설치
npm install nanoid
JavaScript — 짧은 고유 ID를 위한 nanoid
import { nanoid, customAlphabet } from 'nanoid';

// 기본값: 21자 URL 안전 ID (A-Za-z0-9_-)
const trackingCode = nanoid();
console.log(trackingCode);
// "V1StGXR8_Z5jdHi6B-myT"

// 커스텀 길이
const shortCode = nanoid(10);
console.log(shortCode);
// "IRFa-VaY2b"

// 커스텀 알파벳 — 숫자만, 12자리
const numericId = customAlphabet('0123456789', 12);
console.log(numericId());
// "839274651023"

// 커스텀 알파벳 — 16진수만, 32자 (하이픈 없는 UUID v4와 동일한 엔트로피)
const hexId = customAlphabet('0123456789abcdef', 32);
console.log(hexId());
// "4f8a1b2c3d7e9f0a5b6c8d1e2f3a4b5c"

구문 강조를 통한 터미널 출력

UUID가 많은 애플리케이션을 디버깅할 때 터미널에서 16진수 문자열들을 계속 봐야 합니다. 색상 구분이 도움이 됩니다. chalk 라이브러리(또는 Node.js 21.7+의 더 새로운 내장 node:util styleText)를 사용하면 로그 출력에서 UUID를 강조하여 주변 텍스트에서 눈에 띄게 만들 수 있습니다.

Node.js — chalk로 색상이 적용된 UUID 출력
import chalk from 'chalk';
import { randomUUID } from 'node:crypto';

function logEvent(action, metadata = {}) {
  const eventId = randomUUID();
  const timestamp = new Date().toISOString();

  console.log(
    chalk.gray(timestamp),
    chalk.cyan(eventId),
    chalk.white(action),
    Object.keys(metadata).length
      ? chalk.dim(JSON.stringify(metadata))
      : ''
  );
}

logEvent('shipment.created', { order_id: 'ord_8a3f', carrier: 'fedex' });
logEvent('payment.captured', { amount_cents: 14999, currency: 'USD' });
logEvent('webhook.delivered', { endpoint: 'https://hooks.acme.dev/orders' });
// 2026-03-27T10:15:00.000Z  a1b2c3d4-...  shipment.created  {"order_id":"ord_8a3f",...}
경고:색상 이스케이프 코드는 로그 파일을 손상시키고 JSON 파서를 망가뜨립니다. chalk 또는 styleText는 사람이 직접 읽는 터미널 출력에만 사용하세요. 파일이나 로그 집계기로 전달되는 구조화된 로그에는 일반 JSON을 사용하세요.

JavaScript에서 짧은 고유 ID 생성하기

36자 UUID는 때로 너무 깁니다 — URL 슬러그, QR 코드 데이터, SMS 메시지, 임베디드 하드웨어 프로토콜 모두 길이 제약이 있습니다.

JavaScript — 더 짧은 ID를 위한 세 가지 방법
import { randomUUID } from 'node:crypto';

// 1. UUID v4에서 하이픈 제거 → 32자 16진수 문자열
const hex32 = randomUUID().replaceAll('-', '');
console.log(hex32);
// "3e7f1a924b0c4d8e9f127a6b3c8d5e1f" (32자)

// 2. 16개의 무작위 바이트를 Base64로 인코딩 → 22자 (URL 안전)
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
const base64Id = Buffer.from(bytes)
  .toString('base64url')
  .replace(/=+$/, '');
console.log(base64Id);
// "Pj8akksNTY6fEnarPIvR" (22자, 128비트 엔트로피)

// 3. 커스텀 길이의 nanoid
import { nanoid } from 'nanoid';
const short12 = nanoid(12);
console.log(short12);
// "V1StGXR8_Z5j" (12자, ~71비트 엔트로피)

충돌 확률 계산: 12자 nanoid(기본 알파벳 64자)는 약 71비트의 엔트로피를 제공합니다. 초당 1,000개의 ID를 생성하면 1% 충돌 확률에 도달하는 데 약 116년이 필요합니다. 대부분의 애플리케이션에 충분합니다. 하루에 수백만 개의 ID를 생성한다면 전체 UUID를 사용하거나 최소 21자 이상의 nanoid를 사용하세요.

UUID v7 — v4의 시간 순서 대안

UUID v7(RFC 9562에 정의됨)은 첫 번째 세그먼트에 48비트 Unix 밀리초 타임스탬프를 내장하고 이후에 무작위 비트를 넣습니다. 결과는 v4와 비슷하지만 시간순으로 정렬됩니다. 이 때문에 데이터베이스 기본 키로 v4보다 나은 선택입니다: 새 행이 항상 B-트리 인덱스 끝에 위치하여 페이지 분할과 단편화를 줄입니다. Postgres 테이블에 시간 순서 ID가 필요할 때는 즉시 v7으로 전환합니다 — 규모에 따라 인덱스 성능 차이가 측정됩니다. ToolDeck의 UUID v7 생성기 v7 UUID의 내장 타임스탬프를 보여줍니다.

JavaScript — uuid 패키지로 UUID v7 사용
import { v7 as uuidv7 } from 'uuid';

// UUID v7 값 세 개 생성 — 시간순으로 정렬됨을 확인
const id1 = uuidv7();
const id2 = uuidv7();
const id3 = uuidv7();

console.log(id1);
// "018e4a0c-5b3f-7d12-8a9b-0c1d2e3f4a5b"
console.log(id2);
// "018e4a0c-5b40-7e34-9c2d-1e4f5a6b7c8d"
console.log(id3);
// "018e4a0c-5b41-7f56-ae3f-2a5b6c7d8e9f"

// 사전식으로 생성 시간 순서대로 정렬됨
console.log([id3, id1, id2].sort());
// [id1, id2, id3] — 시간 순서 보존

// 타이밍 정보가 노출되어서는 안 되는 토큰에는 v4 사용
import { v4 as uuidv4 } from 'uuid';
const sessionToken = uuidv4(); // 완전 무작위, 타이밍 정보 없음
참고:uuid 패키지는 버전 9.0.0부터 v7을 지원합니다. 이전 버전을 사용 중이라면 npm install uuid@latest로 업그레이드하세요.

빌드 단계 없이 브라우저에서 UUID v4 사용

번들러도, npm도, 트랜스파일러도 없습니다. 순수한 HTML 파일만으로 됩니다. 클라이언트 사이드 JavaScript에서 UUID를 생성하는 가장 간단한 방법입니다. crypto.randomUUID() 내장 브라우저 API이기 때문에 가능합니다.

HTML — 최소한의 브라우저 UUID 생성기
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>UUID Generator</title></head>
<body>
  <p>Your UUID: <strong id="output"></strong></p>
  <button onclick="document.getElementById('output').textContent = crypto.randomUUID()">
    Generate
  </button>
  <script>
    // 페이지 로드 시 하나 생성
    document.getElementById('output').textContent = crypto.randomUUID();
  </script>
</body>
</html>

전체 파일이 이것입니다. CDN import도, 라이브러리를 불러오는 script 태그도 없습니다. 배치 생성, 유효성 검사, 결정론적 ID처럼 더 복잡한 것이 필요하다면 uuid 패키지나 앞서 보여준 수동 폴백이 필요합니다. 하지만 빠른 프로토타입이나 내부 도구라면 이것으로 충분합니다.

흔한 실수들

오래된 블로그 포스트의 Math.random() UUID 패턴이 프로덕션 코드로 복사된 것을 많이 봤습니다. 이런 패턴이 만들어내는 버그는 조용합니다: 런타임 오류가 없고 부하나 보안 검토 시에 나중에 표면화되는 미묘하게 잘못된 동작만 있습니다.

Math.random()을 사용한 UUID 생성

문제: Math.random()은 암호학적으로 안전하지 않습니다. 일부 엔진에서는 출력이 예측 가능하며, 낮은 엔트로피로 인해 제대로 된 CSPRNG보다 충돌이 훨씬 많이 발생합니다.

해결책: 항상 crypto.randomUUID() 또는 crypto.getRandomValues()를 사용하세요. 둘 다 운영 체제의 CSPRNG를 사용합니다.

Before · JavaScript
After · JavaScript
// 안전하지 않음 — 예측 가능하고 낮은 엔트로피
function badUuid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
    /[xy]/g,
    c => {
      const r = Math.random() * 16 | 0;
      return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    }
  );
}
// 안전함 — OS CSPRNG 사용
const id = crypto.randomUUID();

// 수동 폴백이 필요한 경우:
function secureUuid() {
  const bytes = new Uint8Array(16);
  crypto.getRandomValues(bytes);
  bytes[6] = (bytes[6] & 0x0f) | 0x40;
  bytes[8] = (bytes[8] & 0x3f) | 0x80;
  const h = [...bytes].map(b => b.toString(16).padStart(2, '0'));
  return `${h.slice(0,4).join('')}-${h.slice(4,6).join('')}-${h.slice(6,8).join('')}-${h.slice(8,10).join('')}-${h.slice(10).join('')}`;
}
대소문자 구분 동등 비교로 UUID 비교

문제: crypto.randomUUID()는 소문자 16진수를 반환하지만, 다른 시스템(데이터베이스, API, 사용자 입력)의 UUID는 대문자를 사용할 수 있습니다. 대소문자가 다를 경우 직접 === 비교가 실패합니다.

해결책: 비교 전에 양쪽 모두 소문자로 정규화하세요.

Before · JavaScript
After · JavaScript
const fromApi = "9B1DEB4D-3B7D-4BAD-9BDD-2B0D7B3DCB6D"; // API에서 대문자
const local  = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d";  // crypto에서 소문자

if (fromApi === local) { /* 실행되지 않음 */ }
const fromApi = "9B1DEB4D-3B7D-4BAD-9BDD-2B0D7B3DCB6D";
const local  = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d";

if (fromApi.toLowerCase() === local.toLowerCase()) {
  // 올바르게 일치
}
UUID를 문자열 대신 객체로 저장

문제: 일부 UUID 라이브러리(특히 다른 언어)는 UUID 객체를 반환합니다. JavaScript에서 UUID 문자열을 실수로 객체로 감싸면 동등 비교, JSON 직렬화, 데이터베이스 쿼리가 망가집니다.

해결책: 항상 UUID를 일반 문자열로 저장하고 전달하세요. 라이브러리가 객체를 반환하면 즉시 .toString()을 호출하거나 문자열 속성에 접근하세요.

Before · JavaScript
After · JavaScript
// 불필요한 래퍼 생성
class UUID {
  constructor(value) { this.value = value; }
}
const id = new UUID(crypto.randomUUID());
console.log(id === id); // true, 하지만...
console.log(JSON.stringify({ id })); // {"id":{"value":"..."}}
// 문자열만 사용
const id = crypto.randomUUID();
console.log(JSON.stringify({ id }));
// {"id":"3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"}
UUID v4를 정렬 가능한 것으로 취급

문제: UUID v4는 완전히 무작위입니다. UUID v4로 정렬하면 생성 순서가 아닌 임의의 순서가 됩니다. 이는 예측 불가능한 페이지네이션, 혼란스러운 관리자 UI, 나쁜 데이터베이스 인덱스 성능을 초래합니다.

해결책: 시간 순서 식별자가 필요할 때는 UUID v7을 사용하세요. UUID v4는 정렬 순서가 관련 없는 토큰과 상관관계 ID에 유지하세요.

Before · JavaScript
After · JavaScript
// 잘못됨: v4를 정렬 가능한 기본 키로 사용
const rows = [
  { id: crypto.randomUUID(), created: "2026-03-27" },
  { id: crypto.randomUUID(), created: "2026-03-26" },
];
rows.sort((a, b) => a.id.localeCompare(b.id));
// 정렬 순서가 무작위 — 생성 날짜 순서가 아님
import { v7 as uuidv7 } from 'uuid';
// 올바름: v7은 생성 시간으로 정렬
const rows = [
  { id: uuidv7(), created: "2026-03-27" },
  { id: uuidv7(), created: "2026-03-26" },
];
rows.sort((a, b) => a.id.localeCompare(b.id));
// 정렬 순서가 생성 시간과 일치

crypto.randomUUID() vs uuid vs nanoid — 빠른 비교

방법
출력 형식
UUID 버전
번들 크기
커스텀 타입
설치 필요
crypto.randomUUID()
36자 UUID v4
v4만
0 KB
해당 없음
아니오 (내장)
uuid npm 패키지
36자 UUID
v1, v3, v4, v5, v6, v7
~6.5 KB
해당 없음
npm install
nanoid
21자 URL 안전 ID
커스텀 (UUID 아님)
~1 KB
해당 없음
npm install
수동 getRandomValues
36자 UUID v4
v4만
0 KB
해당 없음
아니오 (내장)
crypto.randomBytes (Node)
Buffer → 36자 UUID v4
v4만
0 KB
해당 없음
아니오 (Node 내장)
uuidv7 npm 패키지
36자 UUID v7
v7만
~2 KB
해당 없음
npm install

대부분의 JavaScript 프로젝트에서: 런타임이 최신이고 UUID v4만 필요하다면 crypto.randomUUID()를 사용하세요. v5(결정론적) 또는 v7(시간 순서) 지원이 필요하면 uuid 패키지를 사용하세요. 36자 UUID보다 짧고 URL 안전한 ID가 더 실용적이면 nanoid를 사용하세요 — 하지만 nanoid 출력은 UUID 규격을 따르지 않으며 RFC 4122 형식을 기대하는 시스템에서 검증에 실패한다는 점을 기억하세요.

코드 없는 대안으로는 UUID v4 생성기를 사용하여 브라우저에서 즉시 식별자를 생성할 수 있습니다. 기존 UUID를 검사하려면 UUID 디코더에 붙여넣어 버전, 배리언트, 내장 타임스탬프 데이터를 확인하세요.

자주 묻는 질문

JavaScript에서 UUID v4를 어떻게 생성하나요?

모던 브라우저(Chrome 92+, Firefox 95+, Safari 15.4+) 또는 Node.js 19+에서 crypto.randomUUID()를 호출하면 됩니다. "3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"와 같은 소문자 문자열을 반환합니다. 브라우저에서는 crypto가 전역 내장 객체이므로 import가 필요하지 않습니다. Node.js에서는 전역 crypto 객체를 직접 사용하거나 import { randomUUID } from "node:crypto"로 명시적으로 가져올 수 있습니다. Node.js 19보다 오래된 런타임에서도 crypto.randomUUID()를 전역으로 호출할 수 있습니다 — Node.js 14.17.0부터 실험적으로 지원됩니다. 코드 없이 사용하고 싶다면 /en/uuid/v4의 UUID v4 생성기가 클릭 한 번으로 규격에 맞는 식별자를 생성해 줍니다.

JavaScript
const sessionId = crypto.randomUUID();
console.log(sessionId);
// "3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"

crypto.randomUUID()는 암호학적으로 안전한가요?

네. crypto.randomUUID()는 crypto.getRandomValues()와 동일한 CSPRNG(암호학적으로 안전한 의사 난수 생성기)를 사용합니다. UUID v4에 포함된 122비트의 난수는 충돌 확률을 사실상 무시할 수 있을 만큼 낮게 만듭니다 — 50% 충돌 확률에 도달하려면 약 27.1경 개의 UUID를 생성해야 합니다. 엔트로피는 운영 체제의 난수 소스(Linux의 /dev/urandom, Windows의 BCryptGenRandom)에서 나오며 Math.random()을 사용하지 않습니다. Math.random()은 명시적으로 암호학적으로 안전하지 않습니다. 즉, UUID v4 값은 세션 토큰, CSRF 토큰, 예측 불가능성이 중요한 기타 보안 식별자로 안전하게 사용할 수 있습니다. 보안 컨텍스트에서는 절대 Math.random() 기반 UUID 생성기를 사용하지 마세요.

UUID v4를 데이터베이스 기본 키로 사용할 수 있나요?

사용할 수 있지만 중요한 성능 트레이드오프가 있습니다. UUID v4는 완전히 무작위이므로 각 새 행이 인덱스 끝이 아닌 무작위 위치에 삽입되어 B-트리 인덱스가 심하게 단편화됩니다. 쓰기가 많은 테이블에서는 과도한 페이지 분할과 캐시 미스가 발생하여 INSERT 및 범위 스캔 성능이 저하됩니다. 데이터베이스가 지원하는 경우(PostgreSQL, MySQL 8.0+, SQL Server), UUID v7(시간 순서)이 더 나은 기본 키입니다. 새 행이 항상 인덱스 끝에 추가되기 때문입니다. UUID v4는 세션 토큰, OAuth 상태 매개변수, 멱등성 키, 상관관계 ID, 생성 시간을 숨기는 것이 바람직한 모든 필드에 적합합니다.

JavaScript
// UUID v4 — 무작위, 정렬 불가
const correlationId = crypto.randomUUID();

// UUID v7 — 시간 순서, DB 기본 키에 적합
import { v7 as uuidv7 } from 'uuid';
const rowId = uuidv7();

UUID v4와 UUID v7의 차이점은 무엇인가요?

UUID v4는 122비트를 난수로 채웁니다 — 모든 세그먼트가 사실상 노이즈입니다. UUID v7(RFC 9562, 2024년 발행)은 첫 번째 세그먼트에 48비트 Unix 밀리초 타임스탬프를 인코딩하고, 두 번째 세그먼트에 12비트 서브밀리초 정밀도를 넣으며, 나머지에 난수 비트를 사용합니다. 둘 다 128비트이며 동일한 36자 하이픈 형식을 사용하므로 저장 계층에서 상호 교환 가능합니다. UUID v7은 생성 시간에 따라 사전식으로 정렬되므로 B-트리 인덱스를 컴팩트하게 유지하고 시간 범위 쿼리를 효율적으로 만듭니다. ID가 언제 생성되었는지 드러내서는 안 될 때(예: 타이밍 정보가 악용될 수 있는 공개 토큰)는 UUID v4를 선택하고, 데이터베이스 기본 키, 감사 로그, 이벤트 스트림 등 시간 순서가 중요한 경우에는 UUID v7을 사용하세요.

JavaScript에서 UUID v4 문자열을 어떻게 검증하나요?

/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i 정규식으로 검사하세요. 위치 15(0 인덱스)의 리터럴 "4"는 버전 니블을 확인하고, 위치 20의 문자(8, 9, a, b 중 하나)는 RFC 4122 배리언트 비트를 인코딩합니다. 이 정규식은 UUID v1, v7 및 잘못된 형식의 문자열을 올바르게 거부합니다. i 플래그는 대소문자를 구분하지 않으므로 다른 시스템의 대문자 16진수도 정규화 없이 검증을 통과합니다. 버전에 관계없이 유효한 UUID인지만 확인하려면 /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i 패턴을 사용하세요.

JavaScript
const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;

UUID_V4_RE.test("550e8400-e29b-41d4-a716-446655440000"); // true
UUID_V4_RE.test("550e8400-e29b-11d4-a716-446655440000"); // false (v1)
UUID_V4_RE.test("not-a-uuid"); // false

JavaScript에서 짧은 고유 ID를 어떻게 생성하나요?

UUID v4에서 하이픈을 제거하면 32자 16진수 문자열을 얻을 수 있습니다: crypto.randomUUID().replaceAll("-", ""). 더 짧게 하려면 nanoid를 사용하세요. 기본적으로 21자의 URL 안전 ID(A–Z, a–z, 0–9, _ 및 -)를 생성하며 전체 UUID와 비슷한 충돌 저항성을 가집니다. 트레이드오프는 명확합니다: 짧은 ID는 충돌 확률이 높지만 21자 nanoid는 126비트의 엔트로피를 제공하며 실질적으로 모든 애플리케이션에 충분합니다. URL 슬러그와 QR 코드 페이로드의 경우 일반적인 생성 속도에서 충돌 확률이 문제가 되기 전까지 nanoid로 10–12자까지 줄일 수 있습니다. 원시 UUID를 Base64로 인코딩하고 자르는 방식은 피하세요 — 자르면 비트의 통계적 독립성이 파괴되어 충돌을 추론하기 어려워집니다.

JavaScript
// UUID v4에서 32자 16진수 문자열 생성
const hexId = crypto.randomUUID().replaceAll('-', '');
// "3e7f1a924b0c4d8e9f127a6b3c8d5e1f"

// nanoid를 통한 21자 URL 안전 ID
import { nanoid } from 'nanoid';
const shortId = nanoid();
// "V1StGXR8_Z5jdHi6B-myT"

관련 도구

다른 언어로도 제공됩니다:Python
SL
Sophie LaurentTypeScript & Full-stack Developer

Sophie is a full-stack developer focused on TypeScript across the entire stack — from React frontends to Express and Fastify backends. She has a particular interest in type-safe API design, runtime validation, and the patterns that make large JavaScript codebases stay manageable. She writes about TypeScript idioms, Node.js internals, and the ever-evolving JavaScript module ecosystem.

MW
Marcus Webb기술 검토자

Marcus specialises in JavaScript performance, build tooling, and the inner workings of the V8 engine. He has spent years profiling and optimising React applications, working on bundler configurations, and squeezing every millisecond out of critical rendering paths. He writes about Core Web Vitals, JavaScript memory management, and the tools developers reach for when performance really matters.