What Is a UUID?

A UUID (Universally Unique Identifier) is a 128-bit value used to identify objects without central coordination. Every UUID is represented as 32 hex digits split into 5 groups by hyphens:

550e8400-e29b-41d4-a716-446655440000
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
                ↑
         version nibble (M)

The RFC standard (originally RFC 4122, superseded by RFC 9562 in 2024) defines eight UUID versions. Developers use three of them: v1, v4, and the newer v7. The rest are niche. Understanding what's in those 128 bits determines which one to pick.

UUID v4 — The Safe Default

UUID v4 fills 122 of its 128 bits with cryptographically random data. The remaining 6 bits encode the version and variant. That's it. No timestamp, no node info, no hidden structure.

How it's generated: The OS's CSPRNG (the same entropy source used by TLS) fills a 128-bit buffer. Two fields are then fixed: bits 12–15 are set to 0100 (version 4), and bits 62–63 are set to 10 (RFC 4122 variant). Everything else is random.

UUID v4 is the right choice for:

The only real downside of UUID v4 is database performance when used as a primary key — which UUID v7 was designed to fix.

UUID v1 — Timestamp + MAC Address

UUID v1 was the original standard. It encodes a 60-bit timestamp (100-nanosecond intervals since October 15, 1582 — yes, the Gregorian calendar reform date) plus a 48-bit node identifier, which is typically the generating machine's MAC address.

// v1 structure
xxxxxxxx-xxxx-1xxx-yxxx-xxxxxxxxxxxx
                         ↑
              48-bit node (MAC address or random)

The privacy problem: The node field leaks the MAC address of the machine that generated the UUID. Anyone who receives a UUID v1 can identify the exact network card — and by extension, trace multiple UUIDs back to the same machine. This was one of the discoveries in the Melissa worm investigation in 1999, and it's been a known issue ever since.

When v1 is still used: Internal distributed systems where traceability to a node is desirable rather than a liability. Some legacy databases store v1 UUIDs. Apache Cassandra natively generates v1 UUIDs via now(). If you're working with Cassandra or an existing v1 schema, you keep using v1 — just don't expose them publicly.

The clock sequence problem: If two UUIDs are generated within the same 100-nanosecond window on the same node, v1 increments a clock sequence counter to avoid collision. If the system clock moves backward, the clock sequence is randomized. This means v1 is monotonic within a node under normal conditions but not guaranteed globally.

UUID v7 — The Modern Choice

UUID v7 was finalized in RFC 9562 (May 2024). It takes the best parts of v1 (time-orderability) and v4 (privacy, random suffix) and combines them:

// v7 structure
xxxxxxxx-xxxx-7xxx-yxxx-xxxxxxxxxxxx
↑                 ↑
48-bit Unix ms    74 random bits

The 48 most-significant bits encode the current Unix timestamp in milliseconds (not the 1582 epoch used by v1). The remaining 74 bits (minus version/variant) are cryptographically random.

This gives you:

Side-by-Side Comparison

Property v1 v4 v7
RFC RFC 4122 (2005) RFC 4122 (2005) RFC 9562 (2024)
Generation method Timestamp + MAC address 122-bit CSPRNG random 48-bit Unix ms + 74-bit random
Chronologically sortable Yes (per node) No Yes (globally)
Privacy-safe No — leaks MAC address Yes Yes
DB index performance Good (per node) Poor (random) Excellent
Random bits ~14 bits (clock seq) 122 bits 74 bits
Browser native support No Yes (crypto.randomUUID) No (library required)
Recommended for new projects No Yes (non-DB use) Yes (DB primary keys)

The Database Performance Story

This is where UUID version choice actually matters at scale. Every database engine that uses a B-tree index (PostgreSQL, MySQL, SQLite, SQL Server) organizes index entries in sorted order on disk. When you insert a new row, the database places its key in the correct position in the B-tree.

With UUID v4 as a primary key: Each new UUID inserts into a random position in the B-tree. The database must find a page in the middle of the index, read it, insert the new key, and potentially split the page if it's full. Page splits are expensive: they require writing two new pages to disk and updating pointers. At high insert volumes, this becomes a bottleneck — index pages fragment, cache hit rates drop, and VACUUM has more work to do.

With UUID v7: New UUIDs always sort after previous ones (within millisecond precision). The database appends to the rightmost B-tree leaf page. No page splits, no fragmentation, predictable sequential I/O. The performance profile matches an integer autoincrement.

Real-world impact: At 10M+ rows, UUID v4 primary keys can produce 10–100x more page splits per second than UUID v7 or sequential integer keys. This shows up as increased write latency and larger index sizes. At typical startup scale (millions of rows, not billions), the difference is usually not critical — but it compounds.

Code Examples

JavaScript / Node.js

// UUID v4 — built into browsers and Node.js 19+
const id = crypto.randomUUID();
// "a5f3c8b2-4e1d-4a07-8c9b-2d1e3f4a5b6c"

// UUID v7 — requires the uuid npm package (v10+)
import { v7 as uuidv7 } from 'uuid';
const id = uuidv7();
// "018f1234-abcd-7ef0-8a12-3456789abcde"
//  ↑ first 12 chars encode current Unix ms

// UUID v1 — also in the uuid package
import { v1 as uuidv1 } from 'uuid';
const id = uuidv1();

Python

import uuid

# UUID v4 — built-in
id = str(uuid.uuid4())
# "a5f3c8b2-4e1d-4a07-8c9b-2d1e3f4a5b6c"

# UUID v1 — built-in
id = str(uuid.uuid1())

# UUID v7 — requires python-uuid7 package
# pip install uuid7
from uuid_extensions import uuid7
id = str(uuid7())

# PostgreSQL v7 via psycopg (server-side)
# SELECT gen_uuid_v7()  -- requires pg_uuidv7 extension

Go

// UUID v4 — google/uuid
import "github.com/google/uuid"

id := uuid.New()  // v4
// "a5f3c8b2-4e1d-4a07-8c9b-2d1e3f4a5b6c"

// UUID v7 — google/uuid v1.6+
id, err := uuid.NewV7()
if err != nil {
    log.Fatal(err)
}

// UUID v1
id, err := uuid.NewUUID()  // v1

PostgreSQL

-- UUID v4 — built into Postgres 13+
SELECT gen_random_uuid();

-- UUID v7 — requires the pg_uuidv7 extension
-- https://github.com/fboulnois/pg-uuidv7
CREATE EXTENSION IF NOT EXISTS pg_uuidv7;
SELECT uuid_generate_v7();

-- Use as a default column value
CREATE TABLE users (
  id UUID DEFAULT uuid_generate_v7() PRIMARY KEY,
  email TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

Which Version Should You Use?

The answer depends on what you're doing with the UUID:

Practical default: If you're starting a new project with PostgreSQL or MySQL and you can add a UUID library dependency, use v7 for primary keys and v4 for everything else. If your stack doesn't have a v7 library yet, v4 is still a good choice — it's not broken, just not optimal for B-tree indexes at scale.

What About UUID v3 and v5?

Both use a namespace + name to produce a deterministic UUID. You give them the same input, you get the same UUID back. v3 uses MD5 as the hash; v5 uses SHA-1. Always prefer v5 over v3 since MD5 is considered broken for cryptographic purposes (though the collision risk is low in practice for this use case).

These are useful when you need idempotent ID generation — for example, converting a URL into a stable UUID that's the same every time you process that URL. They're not for general-purpose unique ID generation.

UUID Anatomy Quick Reference

Version Bit layout (128 bits) Sortable Typical use
v1 60b timestamp + 14b clock seq + 6b var + 48b MAC Per-node Legacy, Cassandra
v3 MD5(namespace + name) truncated to 128b No Deterministic IDs (deprecated)
v4 122b random + 6b version/variant No General purpose, tokens, sessions
v5 SHA-1(namespace + name) truncated to 128b No Deterministic IDs, URL hashing
v6 v1 bits reordered for sortability Yes (but still has MAC) v1 migration path — rarely used
v7 48b Unix ms + 74b random + 6b version/variant Yes (globally) DB primary keys, distributed IDs

Ready to generate UUIDs? Our free UUID Generator supports v4 and v1 — completely in-browser, no signup, no limits.

Open UUID Generator

Frequently Asked Questions

What is the difference between UUID v1, v4, and v7?
UUID v1 uses the current timestamp plus the host MAC address. UUID v4 is purely random (122 bits). UUID v7 combines a Unix millisecond timestamp with random bits — giving it the privacy of v4 plus the time-sortability of v1 without leaking any machine identity.
Which UUID version should I use for database primary keys?
UUID v7 is the best choice for new database primary key columns. Its time-ordered nature prevents B-tree index fragmentation, which is the main performance problem with UUID v4 as a primary key. If your UUID library does not support v7 yet, UUID v4 is still acceptable — just be aware of potential index performance issues at scale.
Is UUID v4 still safe to use?
Yes. UUID v4 is the current default for most use cases outside of database primary keys. It provides 122 bits of cryptographic randomness, making it safe for session IDs, API keys, file names, and any identifier that does not need to sort chronologically.
What is UUID v7?
UUID v7 is defined in RFC 9562 (published May 2024). It uses a 48-bit Unix millisecond timestamp in the most-significant bits, followed by 74 random bits. This makes UUIDs sort correctly in chronological order while remaining privacy-safe (no MAC address). Most modern UUID libraries support v7 as of 2024.
Why does UUID v1 expose privacy information?
UUID v1 encodes the generating machine's MAC address in the node field (bits 80–127). Anyone who receives a v1 UUID can determine which network card generated it. For this reason, UUID v1 should not be used in public-facing APIs or any context where the MAC address should not be exposed.
What is B-tree index fragmentation and how does UUID v7 help?
B-tree indexes work efficiently when new keys are appended in order. UUID v4's random values force the database to split existing index pages on every insert — creating fragmentation, extra I/O, and larger index sizes. UUID v7's time-ordered prefix makes inserts sequential at the millisecond level, eliminating the fragmentation problem.
How do I generate UUID v7 in JavaScript?
Browsers do not natively support UUID v7 yet. Use the uuid npm package (v10+): import { v7 as uuidv7 } from 'uuid'; const id = uuidv7(); — Node.js's built-in crypto.randomUUID() only generates v4.
Can UUID v1 and v4 coexist in the same database table?
Yes. All UUID versions share the same 128-bit format and 36-character string representation. They can be stored in the same UUID column without any changes. The version nibble (character 15 in the canonical string) tells you which version was used.
What is the UUID nil value?
The nil UUID is 00000000-0000-0000-0000-000000000000 — all 128 bits set to zero. It is used as a sentinel "null UUID" in some protocols and databases. It is not generated by any UUID version algorithm; it is a special constant defined in RFC 4122.
How many UUIDs can be generated before a collision?
UUID v4 has 2122 ≈ 5.3 × 1036 possible values. To have a 50% probability of a collision you would need to generate approximately 2.71 × 1018 UUIDs. At one billion UUIDs per second, that takes 86 years. Collisions are not a practical concern.