CUID v1 생성기

Generate collision-resistant unique IDs (CUID v1)

개수

생성된 CUID

생성 버튼을 클릭하여 CUID를 만드세요

CUID v1은 레거시 형식입니다. 새 프로젝트에는 CUID2를 사용하세요.

CUID란 무엇인가요?

CUID(충돌 저항 고유 식별자)는 중앙 코디네이터 없이 분산 시스템에서 잘 작동하는 고유 ID를 생성하는 오픈소스 알고리즘입니다. 단순한 UUID와 달리 CUID는 수평 확장 가능하게 설계되었습니다 — 여러 서버 또는 브라우저 탭이 각자 독립적으로 ID를 생성할 수 있으며 충돌 위험이 최소화됩니다.

모든 CUID는 소문자 c로 시작하여 형식을 한눈에 알아볼 수 있습니다. 나머지 문자는 모두 소문자 영숫자(base36)이므로 CUID는 URL 안전하며 추가 인코딩 없이 URL 경로 세그먼트나 데이터베이스 기본 키로 직접 사용할 수 있습니다.

원래 CUID 사양(v1)은 Eric Elliott이 만들었으며 npm 패키지 cuid를 통해 대중화되었습니다. 이제 암호화 보안을 제공하는 CUID v2로 대체되었습니다. 이 페이지와 위의 생성기는 프로덕션 코드베이스에서 여전히 널리 사용되는 클래식 형식인 CUID v1 ID를 생성합니다.

CUID 구조

CUID v1은 약 25자 길이이며 서로 다른 유형의 엔트로피를 가진 5개의 연결 세그먼트로 구성됩니다:

예시: clrc4gkwz001ag2hs3k7f9m2q
c접두사항상 문자 "c" — CUID를 식별함
lrc4gkwz타임스탬프base36의 밀리초 타임스탬프 (~8자)
001a카운터4자 base36 카운터 — 동일 밀리초 충돌 방지
g2hs지문4자 base36 호스트 지문 (브라우저/환경 정보)
3k7f9m2q무작위8자 base36 무작위 블록 — 두 개의 32비트 값

세그먼트는 단순히 연결됩니다 — 구분자가 없습니다. 총 길이는 현재 타임스탬프 값에 따라 약간 다르지만 약 25자를 유지합니다.

CUID가 충돌을 방지하는 방법

충돌 저항은 독립적인 엔트로피 소스를 중첩함으로써 달성됩니다. 최악의 시나리오(많은 머신에서 밀리초당 수천 개의 ID 생성)에서도 두 개의 동일한 ID의 확률이 극히 낮게 유지됩니다.

밀리초 타임스탬프
첫 번째 세그먼트는 현재 시간을 base36으로 인코딩합니다. 다른 시점에 생성된 ID는 생성 시간별로 자동으로 사전순 정렬됩니다 — 페이지네이션과 디버깅에 유용합니다.
단조 카운터
동일한 프로세스 내에서 4자 카운터는 생성된 ID마다 증가합니다. 동일한 머신에서 동일한 밀리초에 두 번의 호출이 발생하더라도 카운터는 밀리초당 최대 65,536개의 ID에 대한 고유성을 보장합니다.
머신 지문
환경별 데이터에서 파생된 해시(Node.js에서는 프로세스 ID + 호스트명; 브라우저에서는 화면 크기 + navigator 정보). 이는 동일한 카운터 값으로 정확히 같은 밀리초에 별도의 호스트에서 생성된 ID를 구분합니다.
무작위 블록
마지막 8자는 base36으로 인코딩된 두 개의 독립적인 32비트 무작위 값에서 나옵니다. 이는 두 머신의 지문이 우연히 동일한 값으로 해시되더라도 충돌을 방지하는 최종 엔트로피 층을 추가합니다.

CUID vs UUID v4

CUID와 UUID v4는 모두 클라이언트 측 ID 생성에 널리 사용됩니다. 동일한 문제에 다른 접근 방식을 취합니다:

특징CUID v1UUID v4
형식c + base36 (~25자)16진수 그룹 (하이픈 포함 36자)
정렬 가능대략적으로 (타임스탬프 접두사)아니오
URL 안전예 (영숫자만)대부분 (하이픈은 URL에서 유효)
충돌 저항높음 — 타임스탬프 + 카운터 + 지문 + 무작위높음 — 122비트 무작위
예측 가능성부분적 (타임스탬프 보임)없음 (순수 무작위)
길이~25자36자
조정 필요아니오아니오

UUID v4는 타이밍 정보를 드러내지 않기 때문에 보안에 민감한 시나리오에서 더 안전한 선택입니다. CUID는 대략 정렬 가능하고 더 짧으며 하이픈이 없는 ID가 필요할 때 유리합니다 — 레코드가 언제 생성되었는지 빠르게 식별하고 싶은 URL, 파일명, 로그에서 편리합니다.

CUID v1 vs CUID2

CUID 사양은 상당히 개정되었습니다. 차이점을 이해하면 프로젝트에 맞는 버전을 선택하는 데 도움이 됩니다:

측면CUID v1CUID v2
알고리즘결정론적 컴포넌트SHA-3 기반, 완전히 불투명
암호화아니오
타임스탬프 가시성아니오
형식"c"로 시작"c"로 시작 (설정 가능)
npm 패키지@paralleldrive/cuid (더 이상 사용 안 함)@paralleldrive/cuid2
길이~25자24자 (기본값, 설정 가능)

새 프로젝트에는 CUID v2가 권장 선택입니다. SHA-3 기반 구성은 출력이 불투명함을 의미합니다 — ID에서 타임스탬프, 카운터, 지문을 역공학할 수 없습니다. 기존 데이터셋과의 하위 호환성이 필요하거나 의존성 없는 구현이 필요한 경우에만 CUID v1을 사용하세요.

사용 사례

분산 데이터베이스
여러 데이터베이스 샤드 또는 마이크로서비스가 시퀀스 테이블이나 중앙 ID 서비스 없이 독립적으로 기본 키를 생성할 수 있어 단일 장애점을 제거합니다.
클라이언트 측 ID 생성
브라우저는 서버로 보내기 전에 새 레코드에 CUID를 할당하여 낙관적 UI 업데이트를 가능하게 하고 서버 할당 ID를 가져오는 왕복을 제거할 수 있습니다.
오프라인 우선 앱
연결 없이 작동하는 모바일 또는 PWA 앱은 동기화를 견디는 안정적인 ID가 있는 레코드를 만들 수 있습니다 — 장치가 다시 온라인 상태가 될 때 충돌 없음.
URL 슬러그
CUID는 영숫자만 포함하여 퍼센트 인코딩 없이 URL 경로에 직접 안전하게 포함할 수 있습니다. 타임스탬프 접두사는 대략적인 생성 시간 순서를 추가합니다.
이벤트 / 로그 상관관계
타임스탬프가 첫 번째 세그먼트에 인코딩되어 있기 때문에 CUID로 태그된 로그 항목은 분산 로그 집계기에서도 생성 시간별로 대략 정렬할 수 있습니다.
ORM / Prisma 기본값
Prisma는 문자열 기본 키에 대한 기본 @id 전략으로 CUID를 사용합니다 — @default(cuid()) — JavaScript 생태계에서 가장 널리 배포된 ID 형식 중 하나입니다.

코드 예시

공식 CUID v2 패키지(권장) 설치 또는 의존성 없는 최소 v1 구현 작성:

JavaScript / TypeScript
// npm install @paralleldrive/cuid2  (recommended — CUID v2)
import { createId } from '@paralleldrive/cuid2'

const id = createId()
// → 'tz4a98xxat96iws9zmbrgj3a'

// Custom length
import { init } from '@paralleldrive/cuid2'
const createShortId = init({ length: 10 })
createShortId() // → 'zxp1l6mf4c'

v1 알고리즘의 의존성 없는 Node.js 구현을 선호하는 경우:

Node.js (no dependencies)
// Pure Node.js — CUID v1 style (no dependencies)
let counter = 0

function pad(str, size) {
  return str.padStart(size, '0').slice(-size)
}

function fingerprint() {
  const os = require('os')
  const source = [process.pid, os.hostname().length].join('')
  let hash = 0
  for (const c of source) {
    hash = ((hash << 5) - hash) + c.charCodeAt(0)
    hash |= 0
  }
  return pad(Math.abs(hash).toString(36), 4)
}

function cuid() {
  const timestamp = Date.now().toString(36)
  const cnt       = pad((counter++ & 0xffff).toString(36), 4)
  const fp        = fingerprint()
  const rnd       = pad(Math.floor(Math.random() * 0xffffffff).toString(36), 4)
              + pad(Math.floor(Math.random() * 0xffffffff).toString(36), 4)
  return 'c' + timestamp + cnt + fp + rnd
}

console.log(cuid()) // → 'clrc4gkwz001ag2hs3k7f9m2q'

Prisma와 PostgreSQL로 CUID를 데이터베이스 기본 키로 사용:

Prisma / SQL
-- Use CUID as a primary key in PostgreSQL
CREATE TABLE users (
  id   TEXT        PRIMARY KEY DEFAULT gen_cuid(),
  name TEXT        NOT NULL,
  created_at TIMESTAMPTZ DEFAULT now()
);

-- Prisma schema (auto-generates CUID by default)
model User {
  id        String   @id @default(cuid())
  name      String
  createdAt DateTime @default(now())
}

자주 묻는 질문

CUID는 URL 안전한가요?
예. CUID v1은 소문자와 숫자(base36 인코딩)만 사용하며, 이는 모두 URL 안전 문자입니다. URL 경로나 쿼리 매개변수에 CUID를 사용할 때 퍼센트 인코딩이 필요하지 않습니다.
CUID는 암호학적으로 안전한가요?
아니오. CUID v1은 Math.random()을 사용하며 가시적인 타임스탬프 접두사를 노출합니다. 세션 토큰이나 비밀번호 재설정 링크와 같은 보안에 민감한 목적에는 적합하지 않습니다. 이러한 사용 사례에는 crypto.randomUUID() 또는 CUID v2를 사용하세요.
CUID vs NanoID — 무엇을 선택해야 하나요?
NanoID는 암호학적으로 안전하고, 더 짧으며(기본 21자), 사용자 정의 가능한 알파벳을 사용합니다. 보안이 중요하거나 더 짧은 ID가 필요할 때 NanoID를 선택하세요. 대략 정렬 가능하고 타임스탬프 접두사가 있는 사람이 디버그할 수 있는 ID가 필요할 때 CUID를 선택하세요.
CUID v1 또는 CUID v2를 사용해야 하나요?
CUID v2가 현재 권장사항입니다. 암호학적으로 안전하고 타이밍 정보를 누출하지 않으며 적극적으로 유지 관리됩니다. CUID v1은 의존성 없는 간단한 구현이 필요하거나 레거시 시스템을 유지 관리할 때 유용합니다. 이 생성기는 CUID v1 ID를 생성합니다.
CUID vs ULID — 무엇이 다른가요?
둘 다 타임스탬프 접두사가 있고 사전순으로 정렬할 수 있습니다. ULID는 Crockford base32(총 128비트, 48비트 타임스탬프 + 80비트 무작위)를 사용하여 약간 더 무작위입니다. CUID는 머신 지문과 단조 카운터를 추가하여 동일한 밀리초 내 같은 호스트에서의 충돌 저항을 향상시킵니다. ULID는 타임스탬프가 전체 상위 부분을 차지하기 때문에 더 안정적으로 정렬됩니다.
CUID는 고유성이 보장되나요?
중앙 코디네이터 없이는 어떤 ID 방식도 수학적 보장을 제공할 수 없습니다. CUID는 타임스탬프, 프로세스당 카운터, 머신 지문, 무작위 데이터라는 네 개의 독립적인 엔트로피 소스를 결합하여 충돌을 극히 드물게 만듭니다. 실제로 충돌은 하드웨어 장애보다 훨씬 가능성이 낮습니다.