CUID v1生成器
Generate collision-resistant unique IDs (CUID v1)
已生成的 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 个字符长,由五个串联段组成,每段承载不同类型的熵:
这些段仅简单串联——没有分隔符。总长度根据当前时间戳值略有变化,但保持在约 25 个字符。
CUID 如何防止碰撞
碰撞抵抗来自于叠加独立的熵源,即使在最坏情况下(每毫秒跨多台机器生成数千个 ID)两个相同 ID 的概率也极低。
CUID vs UUID v4
CUID 和 UUID v4 都广泛用于客户端 ID 生成。它们对同一问题采取不同的方法:
| 特性 | CUID v1 | UUID v4 |
|---|---|---|
| 格式 | c + base36(约 25 字符) | 十六进制组(36 字符含连字符) |
| 可排序 | 大致可排序(时间戳前缀) | 否 |
| URL 安全 | 是(仅字母数字) | 基本上(连字符在 URL 中可用) |
| 碰撞抵抗 | 高——时间戳 + 计数器 + 指纹 + 随机 | 高——122 位随机 |
| 可预测性 | 部分(时间戳可见) | 无(纯随机) |
| 长度 | 约 25 个字符 | 36 个字符 |
| 需要协调 | 否 | 否 |
UUID v4 是安全敏感场景的更安全选择,因为它不泄露时间信息。当你需要大致可排序、更短且无连字符的 ID 时,CUID 更有优势——便于在 URL、文件名或日志中快速识别记录的创建时间。
CUID v1 vs CUID2
CUID 规范已进行了重大修订。了解差异有助于为你的项目选择正确版本:
| 方面 | CUID v1 | CUID v2 |
|---|---|---|
| 算法 | 确定性组件 | 基于 SHA-3,完全不透明 |
| 加密 | 否 | 是 |
| 时间戳可见 | 是 | 否 |
| 格式 | 以 "c" 开头 | 以 "c" 开头(可配置) |
| npm 包 | @paralleldrive/cuid(已弃用) | @paralleldrive/cuid2 |
| 长度 | 约 25 字符 | 24 字符(默认,可配置) |
对于新项目,推荐使用 CUID v2。其基于 SHA-3 的构造意味着输出是不透明的——无法从 ID 中逆向工程时间戳、计数器或指纹。仅在需要与现有数据集向后兼容或需要无依赖实现时才使用 CUID v1。
使用场景
@id 策略——@default(cuid())——使其成为 JavaScript 生态系统中部署最广泛的 ID 格式之一。代码示例
安装官方 CUID v2 包(推荐)或编写无依赖的最小 v1 实现:
// 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 实现:
// 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'使用 CUID 作为 Prisma 和 PostgreSQL 的数据库主键:
-- 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())
}