CUID2 — Collision-Resistant IDs Better Than UUID v4
CUID2 generates secure, URL-safe, database-friendly IDs with better collision resistance than UUID v4. Learn how CUID2 differs from UUID, nanoid, and ULID, with JavaScript and...
Use the tool
UUID Generator
Generate UUID v4 and v7 identifiers in bulk.
CUID2 is a modern ID format designed to fix UUID v4’s weaknesses: poor collision resistance at scale, no timestamp ordering, and potential fingerprinting. It’s shorter than UUID (24 chars), URL-safe, and starts with a letter.
Generate UUID and CUID identifiers with the UUID Generator.
Install and generate
import { createId } from '@paralleldrive/cuid2'; // npm install @paralleldrive/cuid2
const id = createId();
// "clnfkzj2b0000358s9mf01234" (24 chars, lowercase alphanumeric)
// Custom length (default 24, min 2, max 32):
import { init } from '@paralleldrive/cuid2';
const cuid = init({ length: 16 });
const shortId = cuid(); // "clnfkzj2b0000358s"
CUID2 vs UUID v4 vs nanoid vs ULID
| Property | UUID v4 | CUID2 | nanoid | ULID |
|---|---|---|---|---|
| Length | 36 chars | 24 chars | 21 chars | 26 chars |
| Format | Hex + dashes | Alphanumeric | URL-safe | Alphanumeric |
| Sortable | No | No | No | Yes (by time) |
| Starts with letter | No | Yes | Variable | Variable |
| URL-safe | No (-) | Yes | Yes | Yes |
| Timestamp component | No | No | No | Yes |
| Collision resistance | Good | Better | Very good | Good |
| Fingerprint risk | Low | None | None | Low |
// UUID v4 example:
import { v4 as uuid } from 'uuid';
uuid(); // "550e8400-e29b-41d4-a716-446655440000" (36 chars, has dashes)
// CUID2 example:
createId(); // "clnfkzj2b0000358s9mf01234" (24 chars, no dashes)
// nanoid example:
import { nanoid } from 'nanoid';
nanoid(); // "V1StGXR8_Z5jdHi6B-myT" (21 chars, uses URL-safe chars)
// ULID example (time-sortable):
import { ulid } from 'ulid';
ulid(); // "01ARZ3NDEKTSV4RRFFQ69G5FAV" (26 chars, lexicographically sortable)
Why CUID2 is better than UUID v4 at scale
UUID v4: 122 bits of randomness
At 1 billion UUIDs, collision probability ≈ 0.0000000002% (negligible)
At 1 trillion UUIDs, collision probability ≈ 0.00002% (concerning for huge databases)
CUID2: uses SHA-3 hash of entropy pool + counter + timestamp + fingerprint
Better statistical distribution due to hash function
Counter prevents collisions when generating multiple IDs in the same millisecond
For typical apps (< 1 billion records): UUID v4, CUID2, and nanoid are all fine
For large-scale systems: CUID2 or nanoid provide better guarantees
CUID2 structure (how it works)
"clnfkzj2b0000358s9mf01234"
c — always starts with a letter (safe for HTML IDs, CSS classes)
lnfkzj2b — entropy from timestamp
0000 — counter (increments for multiple IDs in same ms)
358s9mf — fingerprint (process/browser fingerprint hash)
01234 — additional random entropy
Total: 24 chars of [a-z0-9]
The fingerprint makes CUID2 safe against ID collisions even when generated in:
- Multiple parallel processes
- Multiple browser tabs
- Distributed servers
Database usage
// Prisma schema with CUID2:
// schema.prisma
/*
model User {
id String @id @default(cuid()) // Prisma uses CUID (v1) — use cuid2 in app code
name String
email String @unique
}
*/
// Better: generate in application code:
import { createId } from '@paralleldrive/cuid2';
import { prisma } from './db';
async function createUser(data) {
return prisma.user.create({
data: {
id: createId(), // CUID2 generated here
...data,
},
});
}
-- PostgreSQL: use TEXT or CHAR(24) for CUID2
CREATE TABLE users (
id CHAR(24) PRIMARY KEY DEFAULT '', -- application generates the ID
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);
-- Index performance: CUID2 starts with 'c' + timestamp bytes
-- B-tree index: decent performance, not as optimal as sequential integer IDs
-- For insert-heavy workloads: consider ULID (sorted) or integer IDs
When to use CUID2 vs alternatives
Use UUID v4 when:
- Standard interoperability is needed (most APIs use UUID)
- You need RFC 4122 compliance
- Team is already familiar with UUID
Use CUID2 when:
- IDs appear in URLs (no dashes, URL-safe)
- IDs appear in HTML/CSS (starts with letter, valid identifier)
- High-scale generation across distributed systems
- Security-conscious: no timestamp component = no info leak
Use ULID when:
- You need time-ordered IDs for better database index locality
- You want lexicographically sortable IDs
Use nanoid when:
- Shortest possible ID (21 chars)
- Custom alphabet needed
- Browser bundle size matters (tiny library)
Use integer/serial IDs when:
- Maximum database performance
- IDs never exposed to users
- Monolithic architecture (no distributed generation)
React / Next.js: generate IDs client-side
// For temporary IDs in UI state (list items, form fields):
import { createId } from '@paralleldrive/cuid2';
import { useState } from 'react';
function TodoList() {
const [todos, setTodos] = useState([]);
function addTodo(text) {
setTodos(prev => [...prev, {
id: createId(), // Temporary ID until server confirms
text,
done: false,
}]);
}
return (/* ... */);
}
Related tools
- UUID Generator — generate UUID v1, v4, v5
- UUID Namespace Versions — UUID v3 and v5 explained
- Password Generator — generate secure random strings
Related posts
- UUID v4 vs v7 for Databases: The Benchmark You Need — UUID v4 fragments your primary key index. UUID v7 fixes it with millisecond-orde…
- NanoID vs UUID — Which Unique ID Generator Should You Use? — NanoID generates shorter, URL-safe unique IDs using a custom alphabet. UUID v4 i…
- ULID Generator — Universally Unique Lexicographically Sortable Identifiers — ULID is a 26-character sortable unique identifier that embeds a millisecond time…
- UUID Versions Explained — v1, v3, v4, v5, and v7 — UUID has multiple versions with different generation strategies. Learn when to u…
Related tool
UUID Generator
Generate UUID v4 and v7 identifiers in bulk.
Written by Mian Ali Khalid. Part of the Dev Productivity pillar.