UUIDs Explained: v4, v7, and When to Use Each as a Primary Key

1 9 115
calendar_todayschedule3 min read

UUID (Universally Unique Identifier) generation seems trivial, but the choice of UUID version, storage format, and primary key strategy significantly affects database performance at scale. Here's what you need to know.

What is a UUID?

A UUID is a 128-bit identifier represented as 32 hexadecimal digits in five groups separated by hyphens:

``

550e8400-e29b-41d4-a716-446655440000

`

The format: 8-4-4-4-12 characters. Total: 36 characters including hyphens (32 hex digits + 4 hyphens).

The version (1–8) appears as the first digit of the third group. The variant bits appear in the fourth group.

For generating UUIDs quickly: use a UUID generator for individual IDs, or the command line for bulk generation.

UUID versions

v1 (timestamp + MAC address): Includes a timestamp and the machine's MAC address. Predictable (contains real MAC address), poor privacy. Rarely used in new systems.

v3 (namespace + MD5): Deterministic — the same input always produces the same UUID. Uses MD5 hashing. Suitable for generating consistent IDs from existing data (e.g., URL → UUID). MD5's collision resistance is weak; prefer v5 for new code.

v4 (random): 122 random bits. This is the most commonly used version — simple, universally supported, no predictability. The downside: purely random, so not time-ordered.

v5 (namespace + SHA-1): Like v3 but uses SHA-1. Use this when you need a deterministic UUID from a namespace and name.

v7 (Unix timestamp + random): New in RFC 9562 (2024). Encodes a 48-bit Unix millisecond timestamp in the most significant bits, followed by random bits. This makes v7 UUIDs monotonically increasing over time — the key advantage for database performance.

Why version matters for databases

UUID v4 inserts into B-tree indexes randomly. Each new row goes to a random position in the index, causing frequent page splits and random disk I/O. At high insert rates, this degrades performance significantly.

UUID v7 inserts are time-ordered. New rows go to the end of the index (since timestamps increase monotonically), similar to an auto-incrementing integer. This results in sequential I/O, dramatically better cache efficiency, and fewer index page splits.

Benchmark comparison (approximate, PostgreSQL):

  • UUID v4: ~30–40% slower inserts vs. BIGINT at high volume
  • UUID v7: near-parity with BIGINT for insert performance
  • UUID v7 also reduces dead tuples from random page splits

For new systems handling significant insert volume, UUID v7 is increasingly recommended as the default primary key type.

Generating UUIDs

JavaScript (Node.js 14.17+ and browsers):

`javascript
// Built-in (no dependencies)


const id = crypto.randomUUID();


// → "550e8400-e29b-41d4-a716-446655440000"

// Node.js alternative

const { randomUUID } = require('crypto');

const id = randomUUID();

`

JavaScript with uuid npm package:

`javascript
import { v4 as uuidv4, v7 as uuidv7 } from 'uuid';

const id4 = uuidv4(); // v4 (random)

const id7 = uuidv7(); // v7 (time-ordered)

`

Python:

`python
import uuid

id4 = str(uuid.uuid4()) # v4 random

"f47ac10b-58cc-4372-a567-0e02b2c3d479"

Deterministic from namespace + name (v5)

id5 = str(uuid.uuid5(uuid.NAMESPACE_URL, "https://example.com"))

`

PostgreSQL (built-in support):

`sql
-- Generate a v4 UUID


SELECT gen_random_uuid();

-- Use as default for a column

CREATE TABLE users (

id UUID DEFAULT gen_random_uuid() PRIMARY KEY,

email TEXT NOT NULL

);

`

MySQL/MariaDB:

`sql
-- Generate UUID (note: returns v1 by default)


SELECT UUID();

-- UUID without dashes

SELECT REPLACE(UUID(), '-', '');

`

Storage: string vs binary

String (VARCHAR(36) or CHAR(36)):

  • Readable, easy to debug
  • 36 bytes per UUID
  • Slower index operations at scale
  • Compatible with all tools and ORMs

Binary (BINARY(16)):
  • 16 bytes per UUID (55% less storage)
  • Faster index lookups — smaller index = more fits in cache
  • MySQL 8+: built-in UUID_TO_BIN() / BIN_TO_UUID() functions
  • Requires conversion in application code

PostgreSQL native UUID type:
  • Stored as 16 bytes internally
  • Displays as 36-character string
  • Best of both — use this when available

`sql
-- PostgreSQL (recommended)
CREATE TABLE orders (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
customer_id UUID NOT NULL REFERENCES customers(id)
); -- MySQL with binary storage CREATE TABLE orders ( id BINARY(16) DEFAULT (UUID_TO_BIN(UUID())) PRIMARY KEY );
` When to use UUID vs auto-increment Use auto-increment (BIGINT) when:
Single-database, no distributed systemMaximum insert performance is criticalNo need to know IDs before insert
Use UUID when:
IDs are generated client-side (offline-first apps)Merging data from multiple systemsExposing IDs in URLs (auto-increment IDs expose row count)Replication or sharding across multiple databasesYou don't want sequential IDs (security through obscurity)
Use UUID v7 specifically when:
You want UUIDs but also need insert performance comparable to BIGINTYou want IDs to be sortable by creation timeYou're building a new system and can choose freely
The nil UUID and max UUID The nil UUID (all zeros):
00000000-0000-0000-0000-000000000000 Used as a sentinel value — "no UUID" or an uninitialized field. Never use it as a real identifier. The max UUID (all ones): ffffffff-ffff-ffff-ffff-ffffffffffff`

Defined in RFC 9562. Used in range queries as an upper bound.


UUID v4 is the safe, universally supported default. If you're building a new system and database performance matters, consider UUID v7 from the start — retrofitting it later requires a migration.

Originally published at https://snappytools.app/uuid-generator/

🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelski - Mar 19

How I Built a React Portfolio in 7 Days That Landed ₹1.2L in Freelance Work

Dharanidharan - Feb 9

The Audit Trail of Things: Using Hashgraph as a Digital Caliper for Provenance

Ken W. Algerverified - Apr 28

Local-First: The Browser as the Vault

Pocket Portfolio - Apr 20

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelski - Apr 23
chevron_left
2.4k Points125 Badges
101Posts
0Comments
SnappyTools builds free, fast, browser-based tools for developers, writers, and designers. No signup... Show more

Related Jobs

View all jobs →

Commenters (This Week)

2 comments
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!