CUID vs UUID vs ULID — Which Should You Use?
- UUID v4: random, 128 bits, universally supported — best default for most projects
- ULID: time-ordered, URL-safe base32, 128 bits — better for sorted queries
- CUID2: collision-resistant, time-prefixed, shorter — good for exposed IDs
- UUID v7: time-ordered UUID format — best of both worlds when you need standard UUID format with sequential ordering
Table of Contents
UUID v4 is the default choice for unique IDs, but ULID and CUID solve specific problems UUID doesn't handle well: sortability, compact representation, and URL-friendliness. Here is a direct comparison of all four formats so you can pick the right one without reading four separate documentation sites.
UUID v4 vs UUID v7 vs ULID vs CUID2 — Side by Side
| Property | UUID v4 | UUID v7 | ULID | CUID2 |
|---|---|---|---|---|
| Format | 8-4-4-4-12 hex | 8-4-4-4-12 hex | 26 base32 chars | 24 alphanumeric |
| Length | 36 chars (with dashes) | 36 chars | 26 chars | 24 chars (configurable) |
| Bits of randomness | 122 | 74 | 80 | ~112+ |
| Time-ordered | No | Yes (ms precision) | Yes (ms precision) | Partial (time prefix) |
| RFC standard | RFC 4122 | RFC 9562 | No | No |
| Database native type | Yes (PG, MSSQL) | PG 17+ | No — store as text | No — store as text |
| URL-safe | With encoding | With encoding | Yes (uppercase base32) | Yes |
| Case-sensitive | No | No | No (case-insensitive) | Yes (lowercase) |
When to Choose Each Format
UUID v4 — choose when:
- Your database has a native UUID type (PostgreSQL, SQL Server)
- You need RFC 4122 compliance
- Randomness and collision resistance are the primary concerns
- You want zero dependencies in most language environments
- The IDs are internal (not user-facing in URLs)
UUID v7 — choose when:
- You want UUID format compatibility (same 36-char representation)
- You need sequential ordering for better database index performance
- PostgreSQL 17+ (built-in uuidv7()) or using a uuid library that supports it
ULID — choose when:
- You need sortable IDs (ULIDs sort lexicographically in the same order they were created)
- You want a shorter, URL-safe representation than UUID
- You are building event-driven systems where temporal ordering matters
CUID2 — choose when:
- You are building user-facing IDs in URLs (shorter, clean alphanumeric)
- You want fingerprinting resistance (no MAC address, no predictable sequences)
- Your ecosystem is Node.js / JavaScript-first (official library: @paralleldrive/cuid2)
Code Examples for Each Format
// UUID v4 — Node.js (no dependencies)
const id = crypto.randomUUID();
// '550e8400-e29b-41d4-a716-446655440000'
// UUID v7 — requires uuid package v9.0+
import { v7 as uuidv7 } from 'uuid';
const id = uuidv7();
// '01956b13-f000-7000-8000-000000000000' (time-ordered)
// ULID — npm install ulid
import { ulid } from 'ulid';
const id = ulid();
// '01ARZ3NDEKTSV4RRFFQ69G5FAV' (sortable, URL-safe)
// CUID2 — npm install @paralleldrive/cuid2
import { createId } from '@paralleldrive/cuid2';
const id = createId();
// 'clh3gfx0e0000jzrmn1b7m42c' (short, alphanumeric)
# Python equivalents import uuid uuid.uuid4() # UUID v4 # UUID v7 — pip install uuid6 import uuid6 uuid6.uuid7() # ULID — pip install python-ulid from ulid import ULID str(ULID()) # sortable time-ordered ID
Short UUID Alternatives — NanoID and Others
If your main concern is length (UUID at 36 chars feels verbose), NanoID is worth knowing:
| Format | Length | Charset | Comparable collision to UUID v4 |
|---|---|---|---|
| UUID v4 | 36 chars (16 bytes) | hex + dashes | 122 bits random |
| NanoID (default) | 21 chars | A-Za-z0-9_- | ~126 bits (more entropy per char) |
| ULID | 26 chars | base32 | 80 bits random + 48 bits time |
| CUID2 (default) | 24 chars | a-z0-9 | ~112 bits |
// NanoID — npm install nanoid
import { nanoid } from 'nanoid';
const id = nanoid(); // 21 chars — default length
const short = nanoid(10); // 10 chars — shorter, less collision resistance
The safe recommendation for most new projects: UUID v7 if your database supports it, UUID v4 otherwise. Only switch to ULID/CUID/NanoID if you have a specific requirement (URL friendliness, sort order) that UUID doesn't meet. See our UUID version guide for more on v4 vs v7.
Generate a UUID v4 for Comparison
See the standard 36-character UUID format side by side with ULID and CUID. Generate a UUID v4 instantly in your browser.
Open Free UUID GeneratorFrequently Asked Questions
Is ULID better than UUID for databases?
ULID has two advantages: it is sortable (newer ULIDs are always greater than older ones, improving index performance) and it is shorter (26 vs 36 characters). The downside: no native database type, no RFC standard, and you must store it as text. UUID v7 achieves the same sequential ordering while maintaining RFC compatibility and native database type support.
What is the difference between CUID and CUID2?
CUID (v1) was deprecated due to fingerprinting vulnerabilities — the time component and process ID were predictable. CUID2 uses a cryptographic hash and removes fingerprinting. Always use @paralleldrive/cuid2, not the original cuid package.
Can I use ULID as a UUID primary key?
You can store a ULID in a UUID column by converting it to UUID format (some ULID libraries support this). But it is usually cleaner to store ULIDs as CHAR(26) or TEXT, or to use UUID v7 if sequential ordering is your goal — v7 is native UUID format with built-in time ordering.

