-
Notifications
You must be signed in to change notification settings - Fork 2
ID CUID
Collision-resistant identifiers — 25 characters, c-prefixed, sortable
within a single process.
CUID (v1) is a 25-character collision-resistant identifier originally proposed by ParallelDrive. The format combines a timestamp, a per-process rolling counter, a per-process fingerprint, and a random tail — giving you:
- Sortable creation order within a single process (timestamp is the highest-order segment).
- Cross-process disambiguation via the fingerprint segment.
- URL- and shell-safe: letters + digits only, no special characters.
-
Self-identifying: the leading
cdistinguishes CUIDs from raw base36 / base62 / hex strings at a glance.
Pairs with Guardian.string().cuid() from @tundralibs/guardian, which
validates the same 25-char c[a-z0-9]{24} format.
Looking for CUID2? Use cuid2 instead — it's cryptographically secure, deliberately not time-sortable (so the minting time can't be reconstructed from the ID), and configurable length. CUID v1 is kept for compatibility and process-local sortability.
c lrwk6yt4 0001 qz2e k6f7r2t1
│ └──────┘ └──┘ └──┘ └──────┘
│ 8 4 4 8
│ timestamp ctr fp random = 24 + leading 'c' = 25
| Component | Length | Description |
|---|---|---|
| Prefix | 1 | Literal c — canonical CUID marker |
| Timestamp | 8 |
Date.now() in base36 |
| Counter | 4 | Per-process rolling counter (base36, mod 36⁴) |
| Fingerprint | 4 | Per-process random base36 string (computed on first call) |
| Random | 8 | Random base36 chars drawn from crypto.getRandomValues
|
| Total | 25 |
CUIDs use lowercase base36: 0-9 followed by a-z. No uppercase, no
special characters — safe for URLs, shell arguments, filenames, and
case-insensitive databases.
Generate a 25-character CUID.
function cuid(): string;string — A 25-character CUID (c + 24 base36 chars).
import { cuid } from '@tundralibs/id';
const id = cuid();
// => "clrwk6yt40001qz2ek6f7r2t1"The function takes no arguments — timestamp, counter, fingerprint, and randomness are all sourced internally.
import { cuid } from '@tundralibs/id';
const userId = cuid();
const orderId = cuid();
const sessionId = cuid();import { cuid } from '@tundralibs/id';
const ids = Array.from({ length: 1000 }, () => cuid());
// Same-process CUIDs sort lexicographically by creation order.
const sorted = [...ids].sort();
console.log(ids.every((id, i) => id === sorted[i])); // trueThe timestamp segment dominates the sort; the counter breaks ties within the same millisecond.
import { cuid } from '@tundralibs/id';
// Needs a separate install: deno add @tundralibs/guardian
import { Guardian } from '@tundralibs/guardian';
const CuidGuard = Guardian.string().cuid();
const id = cuid();
const ok = CuidGuard.parse(id); // round-trips cleanlyUse CUID when:
- You need process-local sortability.
- You want short (25-char) IDs that are URL- and shell-safe.
- You're following an existing CUID convention or migrating from ParallelDrive's reference implementation.
Prefer something else when:
- You need cryptographic collision resistance → use cuid2.
- You need distributed sortability across machines without coordination → use ulid.
- You need MongoDB-native IDs → use ObjectID.
| Aspect | CUID | CUID2 |
|---|---|---|
| Length | 25 chars (fixed) | 24..32 chars (default 24) |
| Prefix | Always c
|
Any letter a..z
|
| Time-sortable | ✅ Within a process | ❌ Deliberately not |
| Randomness source | crypto.getRandomValues |
crypto.getRandomValues |
| Reveals minting time | ✅ Yes (timestamp in prefix) | ❌ No (privacy by design) |
| Collision resistance | High (counter + fingerprint + 8 random chars) | Very high (entire body is random) |
The two formats coexist on purpose — pick CUID when sortability matters, CUID2 when it doesn't.
- Main ID Documentation — Overview of all ID generators
- CUID2 — Cryptographically secure successor
- ULID — Distributed-safe sortable identifiers
- Comparison Guide — Choosing the right ID type
- Original CUID Spec — Reference implementation