Choosing the right unique identifier format for your application is a decision that affects database performance, scalability, and developer experience. With UUID v7 now an official standard (RFC 9562, published 2024), the landscape of ID generation has changed significantly. This guide compares the four most popular options.
Quick Comparison Table
| Feature | UUID v4 | UUID v7 | ULID | NanoID |
|---|---|---|---|---|
| Size (bytes) | 16 | 16 | 16 | Configurable (default 21 chars) |
| String length | 36 chars | 36 chars | 26 chars | 21 chars (default) |
| Time-ordered | No | Yes (ms precision) | Yes (ms precision) | No |
| Standard | RFC 9562 | RFC 9562 | Community spec | Community spec |
| DB index friendly | Poor | Excellent | Excellent | Poor |
| Collision resistance | 122 random bits | 74 random bits + timestamp | 80 random bits + timestamp | Configurable |
| URL-safe | Yes (with encoding) | Yes (with encoding) | Yes (native) | Yes (native) |
| Language support | Universal | Growing rapidly | Good | Excellent (JS/TS) |
UUID v4: The Established Standard
UUID v4 has been the default choice for over a decade. It generates 128-bit identifiers using 122 bits of randomness, producing the familiar xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx format.
Strengths:
- Universal library support in every programming language
- No coordination needed ā generate anywhere, anytime
- Simple and well-understood
Weaknesses:
- Random distribution causes B-tree index fragmentation in databases
- No time information ā cannot sort by creation order
- At scale (millions of rows), insert performance degrades significantly
// JavaScript
crypto.randomUUID();
// ā "f47ac10b-58cc-4372-a567-0e02b2c3d479"Try our UUID Generator tool ā
UUID v7: The New Standard (RFC 9562)
UUID v7, finalized in RFC 9562 (2024), is designed specifically for use as database keys. It combines a 48-bit Unix timestamp (millisecond precision) with 74 bits of randomness, producing time-ordered UUIDs that are fully compatible with existing UUID infrastructure.
Strengths:
- Time-ordered ā naturally sorts by creation time
- Excellent database insert performance (no index fragmentation)
- Compatible with all existing UUID columns and tools
- Native support in PostgreSQL 17+
Weaknesses:
- Fewer random bits (74 vs 122) ā still astronomically collision-resistant
- Timestamp is embedded ā reveals approximate creation time
- Library support still growing (but rapidly)
// Node.js (uuid library v9+)
import { v7 as uuidv7 } from 'uuid';
uuidv7();
// ā "018e4f5c-6a7b-7000-8000-1234abcd5678"
// ^^^^^^^^^^^^^^^^ timestamp portionULID: Lexicographically Sortable
ULID (Universally Unique Lexicographically Sortable Identifier) predates UUID v7 and shares a similar design: 48-bit timestamp + 80 bits of randomness. The key difference is its encoding: Crockford Base32, producing compact 26-character strings like 01ARZ3NDEKTSV4RRFFQ69G5FAV.
Strengths:
- Compact string representation (26 chars vs UUID's 36)
- Built-in monotonicity ā IDs generated in the same millisecond are still ordered
- Lexicographically sortable as strings (no special comparison needed)
- Case-insensitive and URL-safe
Weaknesses:
- Not an RFC standard ā community specification only
- Not compatible with UUID columns without conversion
- Less library support than UUID
// JavaScript
import { ulid } from 'ulid';
ulid();
// ā "01ARZ3NDEKTSV4RRFFQ69G5FAV"NanoID: Compact and Customizable
NanoID takes a different approach: instead of a fixed format, it generates compact, URL-safe random strings with a configurable alphabet and length. The default is 21 characters using A-Za-z0-9_-.
Strengths:
- Very compact (21 chars default, customizable)
- URL-safe by default
- Customizable alphabet and length
- Tiny library (~130 bytes gzipped) ā perfect for frontend
- Cryptographically strong (uses crypto.getRandomValues)
Weaknesses:
- No time-ordering ā same B-tree fragmentation issues as UUID v4
- No standard specification
- Not compatible with UUID infrastructure
// JavaScript
import { nanoid } from 'nanoid';
nanoid();
// ā "V1StGXR8_Z5jdHi6B-myT"Decision Guide: Which Should You Choose?
Use UUID v7 when:
- Building a new application with a relational database
- You need time-ordered IDs for efficient indexing
- Your system expects standard UUID format (PostgreSQL, MySQL, etc.)
- You want the best balance of compatibility and performance
Use UUID v4 when:
- Working with systems that only support UUID v4
- You need maximum randomness with no timestamp leakage
- Database scale is small-to-medium (< 1M rows)
Use ULID when:
- You need shorter string representations
- Working with systems that sort strings lexicographically
- Monotonicity within the same millisecond is important
- You don't need UUID column compatibility
Use NanoID when:
- Generating IDs in the browser or frontend
- Bundle size matters (NanoID is 130 bytes)
- You need short, URL-friendly identifiers
- Building URL shorteners, invite codes, or session tokens
Performance Benchmark: Database Inserts
The most impactful difference between these formats is database insert performance. Time-ordered IDs (UUID v7, ULID) maintain sequential B-tree inserts, while random IDs (UUID v4, NanoID) cause random page splits:
| ID Format | 1M Inserts (PostgreSQL) | Index Size | Insert Pattern |
|---|---|---|---|
| Auto-increment | ~12s (baseline) | 21 MB | Sequential |
| UUID v7 | ~15s (+25%) | 56 MB | Nearly sequential |
| ULID | ~15s (+25%) | 56 MB | Nearly sequential |
| UUID v4 | ~28s (+133%) | 56 MB | Random |
| NanoID (21 chars) | ~30s (+150%) | 62 MB | Random |
Benchmark data is approximate and varies by hardware, database version, and table structure. The relative difference is consistent across environments.
Migration Path: UUID v4 to UUID v7
If you're considering migrating from UUID v4 to UUID v7, the good news is they share the same 128-bit format and string representation. In most databases, you can start generating UUID v7 values for new rows while existing UUID v4 values remain valid:
-- PostgreSQL 17+
CREATE TABLE users (
id UUID DEFAULT gen_random_uuid_v7() PRIMARY KEY,
name TEXT NOT NULL
);
-- Older PostgreSQL with uuid-ossp or pgcrypto
-- Use application-level UUID v7 generationFrequently Asked Questions
Should I migrate from UUID v4 to UUID v7?
If your application uses UUIDs as database primary keys and you experience index fragmentation or slow inserts at scale, migrating to UUID v7 is worth considering. For small-to-medium apps, UUID v4 works fine.
Is NanoID safe for database primary keys?
NanoID is cryptographically secure and has a configurable length, but it lacks time-ordering. For database primary keys where insert performance matters, UUID v7 or ULID are better choices. NanoID shines in frontend applications and URL shorteners.
What is the difference between UUID v7 and ULID?
Both are time-ordered unique identifiers. UUID v7 follows RFC 9562 and is compatible with existing UUID infrastructure (128-bit, standard format). ULID uses Crockford Base32 encoding (26 characters) and has built-in monotonicity within the same millisecond. UUID v7 is better for systems expecting UUID format; ULID is more compact as a string.