Generador CUID2
Genera identificadores CUID2 seguros de próxima generación
CUID2s generados
¿Qué es CUID2?
CUID2 (ID Único Resistente a Colisiones, versión 2) es el sucesor de nueva generación de CUID v1, diseñado para generar IDs cortos, criptográficamente seguros y opacos que son seguros para usar como claves primarias en bases de datos, URLs y sistemas distribuidos.
A diferencia de su predecesor, CUID2 no revela información sobre el momento de creación, la máquina host o el proceso que lo generó. Cada ID es una cadena aparentemente aleatoria que comienza con una letra minúscula aleatoria seguida de un hash base-36 derivado de SHA-512. La longitud predeterminada es 24 caracteres, pero puedes configurarla entre 2 y 32 caracteres según tus restricciones de almacenamiento.
CUID2 es ampliamente recomendado por los kits de herramientas de bases de datos modernas. Prisma lo adoptó como estrategia de ID predeterminada para su escalar @default(cuid()), y PlanetScale, Neon y otros proveedores de bases de datos sin servidor mencionan explícitamente CUID2 como formato de ID preferido porque evita las vulnerabilidades de escaneo secuencial de los enteros autoincrement mientras es más corto y legible que un UUID.
Por Qué CUID2 Reemplazó a CUID v1
CUID v1, lanzado en 2012 por Eric Elliott, fue una mejora importante sobre los UUIDs simples para la generación de IDs del lado del cliente. Sin embargo, los investigadores de seguridad descubrieron dos problemas fundamentales con su diseño:
- Huella digital: La huella digital del host incrustada en cada valor CUID v1 podía usarse para identificar la máquina o proceso que generó el ID, filtrando metadatos operacionales a cualquiera que pudiera observar los IDs.
- Predecibilidad: Dado que CUID v1 incorporaba un contador monótonamente creciente y un segmento de timestamp, un atacante que observara varios IDs podría predecir el rango aproximado de IDs futuros, habilitando ataques de enumeración contra APIs que usan IDs como único control de autorización.
- Hash no criptográfico: CUID v1 usaba un paso de hash no criptográfico simple que no cumplía los estándares de seguridad modernos.
Eric Elliott, el autor original, formalmente deprecó CUID v1 y creó CUID2 desde cero para abordar todos estos problemas. El nuevo algoritmo usa la Web Crypto API (SHA-512) y elimina todos los componentes deterministas, haciendo que cada ID sea estadísticamente independiente de todos los demás.
Principios de Diseño de CUID2
CUID2 vs CUID v1 — Comparación
La tabla a continuación resume las diferencias clave entre CUID2 y el ahora obsoleto CUID v1. Si actualmente usas CUID v1, se recomienda encarecidamente migrar a CUID2.
| Atributo | CUID2 | CUID v1 |
|---|---|---|
| Seguridad | Criptográfico (SHA-512) | No criptográfico (basado en huella digital) |
| Predecibilidad | Opaco — sin metadatos filtrados | Timestamp + huella digital visible en el ID |
| Longitud | Configurable (2–32 chars) | Fija 25 chars |
| Prefijo | Letra aleatoria a–z | Siempre comienza con "c" |
| Distribución | Plana / uniforme | Segmentos monótonamente crecientes |
| Estado | Mantenido activamente | Deprecado por el autor original |
CUID2 vs UUID v4 — Comparación
UUID v4 es el estándar dominante para IDs únicos aleatorios. CUID2 ofrece varias ventajas prácticas sobre UUID v4 sin sacrificar seguridad.
| Atributo | CUID2 | UUID v4 |
|---|---|---|
| Longitud predeterminada | 24 caracteres | 36 caracteres (con guiones) |
| Seguro para URL | Sí — minúsculas a–z + 0–9 | Requiere codificación (contiene guiones) |
| Longitud personalizada | Sí (2–32) | No — siempre 128 bits / 36 chars |
| Ordenable | No (por diseño) | No (v4 es aleatorio) |
| Fuente de entropía | SHA-512 + Web Crypto | CSPRNG |
| Conjunto de caracteres | Base-36 (a–z, 0–9) | Hex + guiones |
El principal compromiso es la familiaridad: UUID v4 es un estándar IETF (RFC 4122) reconocido por prácticamente todas las bases de datos, lenguajes de programación y frameworks de API. CUID2 es un estándar comunitario con soporte creciente pero no universal. Elige UUID v4 cuando la interoperabilidad con sistemas externos es primordial; elige CUID2 cuando controlas ambos extremos y prefieres IDs más cortos y seguros para URL.
Quién Usa CUID2
CUID2 ha visto una adopción rápida en el ecosistema moderno de JavaScript y TypeScript:
- Prisma — el ORM de TypeScript más popular usa CUID2 como predeterminado recomendado para los campos
@idcon@default(cuid())en Prisma Schema v2+. - PlanetScale — su documentación y plantillas de inicio recomiendan CUID2 para claves primarias generadas por la aplicación para evitar problemas de rendimiento de escaneo secuencial en su plataforma MySQL distribuida.
- Drizzle ORM — proporciona un helper predeterminado integrado
cuid2()para definiciones de columnas. - Plantillas tRPC — muchas plantillas comunitarias de tRPC + Prisma se distribuyen con CUID2 como estrategia de clave primaria.
- T3 Stack — la herramienta de scaffolding create-t3-app usa Prisma con valores predeterminados CUID2 en los archivos de esquema generados.
Ejemplos de Código
El paquete oficial npm @paralleldrive/cuid2 proporciona una API simple:
import { createId } from '@paralleldrive/cuid2'
// Generate a single CUID2 (default length: 24)
const id = createId()
console.log(id) // e.g. "tz4a98xxat96iws9zmbrgj3a"
// Custom length
import { init } from '@paralleldrive/cuid2'
const createShortId = init({ length: 16 })
const shortId = createShortId()
console.log(shortId) // e.g. "tz4a98xxat96iws9"Usando CUID2 con el esquema de Prisma:
model User {
id String @id @default(cuid())
email String @unique
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}Generando CUID2 en Node.js sin el paquete npm (usando solo la Web Crypto API, como hace esta herramienta en el navegador):
async function generateCuid2(length = 24) {
const alphabet = 'abcdefghijklmnopqrstuvwxyz'
// Random prefix letter
const firstByte = crypto.getRandomValues(new Uint8Array(1))[0]
const firstChar = alphabet[firstByte % 26]
// Random 32-byte salt
const salt = crypto.getRandomValues(new Uint8Array(32))
const saltHex = [...salt].map(b => b.toString(16).padStart(2, '0')).join('')
// SHA-512 of timestamp + salt
const input = Date.now().toString(36) + saltHex
const hashBuffer = await crypto.subtle.digest(
'SHA-512',
new TextEncoder().encode(input)
)
// Encode hash bytes as base-36 string
const bytes = new Uint8Array(hashBuffer)
let hash = ''
for (let i = 0; i < bytes.length; i += 8) {
let chunk = 0n
for (let j = 0; j < 8 && i + j < bytes.length; j++) {
chunk = (chunk << 8n) | BigInt(bytes[i + j])
}
hash += chunk.toString(36)
}
return (firstChar + hash).slice(0, length)
}
// Usage
const id = await generateCuid2()
console.log(id) // e.g. "m7k3r9p2nxq8zt5a6cwj4bvd"