Need a unique identifier that won't collide even across distributed systems with no coordination? UUIDs (Universally Unique Identifiers) are your answer.
What Are UUIDs/GUIDs?
A UUID (Universally Unique Identifier) is a 128-bit identifier designed to be unique across space and time without requiring a central authority.
550e8400-e29b-41d4-a716-446655440000
GUID (Globally Unique Identifier) is Microsoft's name for the same thing. UUID and GUID are functionally identical.
The standard format is 32 hexadecimal digits displayed in 5 groups separated by hyphens:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
8 4 4 4 12 characters
Where:
Mindicates the UUID version (1-5)Nindicates the variant (usually 8, 9, a, or b)
UUID Versions
Version 1: Time-Based
Generated from timestamp and MAC address:
time_low-time_mid-time_hi_and_version-clock_seq-node
Pros:
- Sortable by creation time
- Guaranteed unique on same machine
Cons:
- Exposes MAC address (privacy concern)
- Predictable (security concern)
- Requires synchronized clocks in distributed systems
Version 2: DCE Security
Rarely used. Similar to v1 but includes POSIX UID/GID.
Version 3: Name-Based (MD5)
Generated by hashing a namespace and name with MD5:
UUIDv3(namespace, "example.com") → always same result
Pros: Deterministic (same input = same UUID) Cons: MD5 is cryptographically weak
Version 4: Random
Generated from random numbers:
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
Where y is 8, 9, a, or b.
Pros:
- Simple to generate
- No privacy concerns
- Most widely used
Cons:
- Not sortable
- Slightly higher (but still negligible) collision probability
Version 5: Name-Based (SHA-1)
Like v3 but uses SHA-1 instead of MD5:
UUIDv5(namespace, "example.com") → always same result
Preferred over v3 for new applications.
Newer Versions (v6, v7, v8)
Recently standardized (RFC 9562):
- v6: Reordered v1 for better database sorting
- v7: Unix timestamp + random, sortable, recommended for new projects
- v8: Custom format for specific use cases
UUID v4: Random Generation
UUID v4 is the most common choice. Generation is simple:
// Node.js
const { randomUUID } = require('crypto');
const uuid = randomUUID();
// Browser
const uuid = crypto.randomUUID();
// Or using a library
const { v4: uuidv4 } = require('uuid');
const uuid = uuidv4();
A v4 UUID looks like:
f47ac10b-58cc-4372-a567-0e02b2c3d479
^ ^
| +-- Variant (8, 9, a, or b)
+------- Version (4)
UUID Format and Structure
550e8400-e29b-41d4-a716-446655440000
│ │ │ │ │
│ │ │ │ └── Node (48 bits)
│ │ │ └─────── Clock sequence (16 bits, variant in top bits)
│ │ └──────────── Time high + version (16 bits)
│ └───────────────── Time mid (16 bits)
└────────────────────────── Time low (32 bits)
For v4, most of this is random data—only the version and variant bits are fixed.
Collision Probability
With 122 random bits in a v4 UUID, the collision probability is astronomically low.
Birthday problem math:
- Generate 1 billion UUIDs per second
- Continue for 100 years
- Probability of one collision: ~50%
More practically:
- 103 trillion UUIDs for 50% collision chance
- With 1 million UUIDs: ~0.00000000006% collision chance
For all practical purposes, UUID v4 collisions don't happen.
UUIDs vs Auto-Increment IDs
| Feature | UUID | Auto-Increment |
|---|---|---|
| Length | 36 chars / 16 bytes | Variable (depends on max) |
| Generation | Client or server | Server only |
| Predictability | Unpredictable | Sequential |
| Merging databases | Easy | Conflicts |
| URL exposure | Safe | Reveals count/order |
| Index performance | Worse (random) | Better (sequential) |
When to Use UUIDs
- Distributed systems without coordination
- Security-sensitive (don't reveal record count)
- Offline-capable applications
- Microservices architecture
- When merging databases later
When to Use Auto-Increment
- Single database, single app
- Performance-critical with many inserts
- Simpler debugging (smaller numbers)
- Foreign keys with clear ordering
UUIDs in Databases
Storage Considerations
A UUID as string: 36 bytes A UUID as binary: 16 bytes
-- String storage (simple but larger)
CREATE TABLE users (
id VARCHAR(36) PRIMARY KEY,
...
);
-- Binary storage (efficient but less readable)
CREATE TABLE users (
id BINARY(16) PRIMARY KEY,
...
);
-- PostgreSQL has native UUID type
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
...
);
Index Performance
Random UUIDs cause scattered inserts, fragmenting B-tree indexes.
Solutions:
- Use UUID v7 (timestamp-prefixed, sortable)
- Use ULID (sortable alternative)
- Accept the trade-off for other benefits
- Use composite keys with sortable prefix
PostgreSQL Example
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE TABLE orders (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
customer_id UUID NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
MySQL Example
CREATE TABLE orders (
id CHAR(36) PRIMARY KEY,
customer_id CHAR(36) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Or use BINARY(16) for efficiency
GUID Formatting Options
GUIDs/UUIDs can be formatted differently:
Standard: 550e8400-e29b-41d4-a716-446655440000
Braces: {550e8400-e29b-41d4-a716-446655440000}
URN: urn:uuid:550e8400-e29b-41d4-a716-446655440000
No dashes: 550e8400e29b41d4a716446655440000
Uppercase: 550E8400-E29B-41D4-A716-446655440000
All represent the same 128-bit value.
When to Use UUIDs
Good Use Cases
✅ Primary keys in distributed systems ✅ External-facing identifiers (API resources) ✅ Session tokens and nonces ✅ File names that shouldn't be guessable ✅ Correlation IDs for logging ✅ Idempotency keys
Bad Use Cases
❌ High-performance sequential access ❌ When integers would suffice ❌ URL slugs (use human-readable names) ❌ When you need ordering
Performance Considerations
Generating UUIDs
UUID generation is fast—typically microseconds:
console.time('uuid');
for (let i = 0; i < 1000000; i++) {
crypto.randomUUID();
}
console.timeEnd('uuid'); // ~200ms for 1M UUIDs
Database Implications
Random UUIDs as primary keys:
- Insert performance: ~10-30% slower than sequential
- Index size: Larger than integer indexes
- Query by PK: Same performance
- Range queries: Not applicable (no natural order)
Consider UUID v7 for better insert performance with maintained benefits.
Summary
- UUID: 128-bit identifier, globally unique without coordination
- GUID: Microsoft's name for UUID (same thing)
- v4: Random, most common, recommended for general use
- v7: Timestamp + random, sortable, recommended for databases
- Collisions: Effectively impossible in practice
- Trade-offs: Larger than integers, random index distribution
Choose UUIDs when you need:
- Distributed generation
- Non-sequential identifiers
- Merge-friendly IDs
- Unpredictable identifiers
Need to generate UUIDs? Try our UUID Generator!