UUID vs GUID: Versions, Differences, and When to Use Each
If you’ve ever needed a unique identifier — for a database row, an API resource, a file, or a distributed system event — you’ve likely encountered both “UUID” and “GUID.” Are they different things? Which version should you use? Let’s clear it up.
UUID vs GUID: The Same Thing
UUID (Universally Unique Identifier) and GUID (Globally Unique Identifier) are the same thing. UUID is the standard term defined in RFC 4122 (and its successor RFC 9562), while GUID is Microsoft’s name for the same concept. The format, generation algorithms, and uniqueness guarantees are identical.
The standard format is 32 hexadecimal digits displayed in five groups separated by hyphens:
550e8400-e29b-41d4-a716-446655440000
This gives 2^128 possible values — approximately 3.4 × 10^38 unique identifiers.
UUID Versions
Not all UUIDs are created equal. The version number (the first digit of the third group) tells you how it was generated:
Version 1 — Timestamp + MAC Address
Combines a 60-bit timestamp (100-nanosecond intervals since October 15, 1582) with the machine’s MAC address.
- Pro: Time-ordered, contains creation metadata
- Con: Leaks the creator’s MAC address (privacy concern), requires access to system clock and network interface
- Use case: Legacy systems that need time-ordered IDs
Version 4 — Random
Generated entirely from random or pseudo-random numbers (122 random bits).
- Pro: Simple, no dependencies, no information leakage
- Con: Not sortable by creation time, random distribution hurts database index performance
- Use case: General-purpose identifiers, session tokens, API keys
- Collision risk: ~50% chance of one collision after generating 2.71 × 10^18 UUIDs
Version 7 — Timestamp + Random (NEW)
The newest version (RFC 9562, 2024). Embeds a Unix timestamp in milliseconds in the first 48 bits, followed by random data.
- Pro: Time-sortable, no MAC address leakage, excellent for database primary keys
- Con: Newer standard, not yet universally supported
- Use case: Database primary keys (especially B-tree indexes), event IDs, anywhere you need both uniqueness and time ordering
Which Version Should You Use?
| Use case | Recommended version |
|---|---|
| Database primary key (SQL) | v7 — sortable, great index locality |
| Database primary key (NoSQL) | v7 or v4 — depends on the database |
| API resource identifier | v4 — simple, no information leakage |
| Session/correlation ID | v4 — unpredictable, random |
| Distributed event ordering | v7 — time-sortable across services |
| Legacy system compatibility | v1 or v4 — depends on what the system expects |
Code Examples
JavaScript
// UUID v4 (built-in, no library needed)
crypto.randomUUID()
// "3b241101-e2bb-4d7a-8613-e0b2a4f9b264"
// UUID v7 (using the 'uuid' package)
import { v7 as uuidv7 } from 'uuid';
uuidv7()
// "018e5b6c-d3a0-7f32-b5e1-4a9c3f2d1b08"
// Validate a UUID
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
UUID_REGEX.test('550e8400-e29b-41d4-a716-446655440000') // true
Python
import uuid
# UUID v4 (random)
uuid.uuid4()
# UUID('a3b45c78-1234-4def-8abc-9e8f7a6b5c4d')
# UUID v1 (timestamp + MAC)
uuid.uuid1()
# UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
# Parse and validate
try:
parsed = uuid.UUID('550e8400-e29b-41d4-a716-446655440000')
print(parsed.version) # 4
except ValueError:
print("Invalid UUID")
# UUID to string and back
my_uuid = uuid.uuid4()
as_string = str(my_uuid) # '3b241101-e2bb-4d7a-8613-e0b2a4f9b264'
as_bytes = my_uuid.bytes # b'\x3b\x24\x11\x01...' (16 bytes)
Go
import "github.com/google/uuid"
// UUID v4
id := uuid.New()
fmt.Println(id.String()) // "3b241101-e2bb-4d7a-8613-e0b2a4f9b264"
// UUID v7
id7, _ := uuid.NewV7()
fmt.Println(id7.String())
// Parse and validate
parsed, err := uuid.Parse("550e8400-e29b-41d4-a716-446655440000")
if err != nil {
log.Fatal("invalid UUID")
}
fmt.Println(parsed.Version()) // 4
SQL (PostgreSQL)
-- UUID v4 (built-in since PostgreSQL 13)
SELECT gen_random_uuid();
-- Use as primary key
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- For UUID v7, use the pg_uuidv7 extension
CREATE EXTENSION IF NOT EXISTS pg_uuidv7;
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
payload JSONB
);
Bash
# Generate UUID v4 (Linux)
cat /proc/sys/kernel/random/uuid
# Generate UUID v4 (macOS/Linux with uuidgen)
uuidgen
# Generate UUID v4 with Python one-liner
python3 -c "import uuid; print(uuid.uuid4())"
UUIDs as Database Primary Keys
This is where the version choice matters most. With B-tree indexes (used by PostgreSQL, MySQL, SQLite), random v4 UUIDs cause index fragmentation because new entries are inserted at random positions in the tree. This leads to more page splits and slower inserts at scale.
V7 UUIDs solve this because their time-ordered prefix means new entries are always appended near the end of the index — similar to auto-increment integers but without coordination.
PostgreSQL tip: Use the gen_random_uuid() function for v4, or use a library like pg_uuidv7 for v7 UUIDs.
UUID String vs Binary Storage
A UUID as a string (550e8400-e29b-41d4-a716-446655440000) takes 36 bytes. As binary, it takes only 16 bytes. In databases:
- PostgreSQL: Use the native
uuidtype (stored as 16 bytes) - MySQL: Use
BINARY(16)orCHAR(36)depending on query patterns - SQLite: Store as
TEXT(no native UUID type) - MongoDB:
BinDatasubtype 4 (16 bytes) or string (36 bytes)
Always use the database’s native UUID type when available — it’s more storage-efficient and enables UUID-aware operations.
Alternatives to UUID
| Format | Length | Sortable | Unique | Use case |
|---|---|---|---|---|
| UUID v4 | 36 chars | No | Yes | General purpose |
| UUID v7 | 36 chars | Yes | Yes | Database keys |
| ULID | 26 chars | Yes | Yes | Compact sortable IDs |
| NanoID | 21 chars | No | Yes | URL-friendly short IDs |
| CUID2 | 24 chars | No | Yes | Secure, collision-resistant |
| Snowflake ID | 18 digits | Yes | Yes | Twitter/Discord-style (requires coordinator) |
If you need shorter IDs and don’t need RFC compliance, ULID and NanoID are popular alternatives. If you’re in an ecosystem that expects UUIDs (most databases, APIs, and frameworks), stick with UUID v4 or v7.
Try It Yourself
Use our UUID Generator to generate v4 (random) or v7 (sortable) UUIDs instantly — with batch generation for creating multiple UUIDs at once.
You might also find the Hash Generator useful for creating deterministic identifiers from known inputs, or check out how JWT tokens use UUIDs for session identification.
Further Reading
- RFC 9562 — New UUID Formats (UUIDv7 specification, 2024)
- RFC 4122 — Original UUID specification (2005)
- pg_uuidv7 — UUID v7 extension for PostgreSQL
- The Problem with UUIDs — PostgreSQL UUID vs serial performance comparison