Databases

UUID v4 vs v7 vs v1 — Which UUID Version Should You Use?

UUID v1, v4, and v7 explained — how they're generated, when each is right, why v4 is the default but v7 is taking over, and the database performance gap nobody warns about.

A UUID is a 128-bit identifier — 16 bytes, written as 36 characters with dashes:

550e8400-e29b-41d4-a716-446655440000

There are several versions (1, 3, 4, 5, 7, 8), each generated differently. Most developers default to v4 because it is the obvious random one. But picking the right version matters more than most people realize, especially if the UUID becomes a database primary key.

This is a practical guide to picking the right one in 2026.


TL;DR

Use case Use Why
You just need a unique ID for an in-memory object v4 Simple, random, no setup
Database primary key v7 Time-ordered, B-tree friendly
Deterministic ID from a name (URL, email, namespace) v5 Hash-based, reproducible
Anything new in 2026 v7 Best of v1 (ordering) and v4 (privacy)
Legacy compatibility (existing v1 / v4 system) Match what is already there Mixing versions is fine but confusing

If you're starting today and you don't know which to pick, use v7.


How Each Version Is Generated

v1 — Time + MAC address

UUID v1 is built from two pieces:

  1. A 60-bit timestamp (100-nanosecond units since 1582).
  2. The MAC address of the machine that generated it.
fdda765f-fc57-5604-a269-52a7df8164ec

Pro: Sortable by creation time. Globally unique without coordination. Con: Leaks the host's MAC address. Considered a mild privacy issue, which is why v4 became the default. Many libraries randomize the MAC bits now, defeating the original guarantee.

v4 — Random

UUID v4 is just 122 bits of randomness, with 6 bits reserved to identify it as v4.

550e8400-e29b-41d4-a716-446655440000

Pro: Trivial to generate. Zero coordination. Effectively impossible to collide if your RNG is good (2¹²² possibilities). Con: Random order — terrible for database indexes that store millions of rows (more on this below).

v5 — Name-based (SHA-1 hash)

UUID v5 is deterministic: same inputs → same UUID. It hashes a name within a namespace.

import uuid
uuid.uuid5(uuid.NAMESPACE_URL, "https://example.com/page")
# Always: cfbff0d1-9375-5685-968a-48ce8b50e3e0

Pro: Two systems can independently compute the same UUID from the same input. Great for deduplication and stable IDs from URLs. Con: Not random, not unique — collisions are deterministic.

v7 — Time-ordered random (2024 spec)

UUID v7 is the modern recommendation. The first 48 bits are a Unix timestamp in milliseconds; the rest is random.

01890b6f-ce47-7c25-8a8d-3c8c7d3e9a4f
└─── time ────┘ └──── random ────┘

Pro: Sortable by time like v1, random like v4, no MAC leak, B-tree-friendly inserts. Con: Newer — some older libraries don't support it yet (most do as of 2025).


The Database Performance Gap Nobody Tells You About

If your UUID is a primary key, the version matters a lot. Here is why.

Databases store rows in B-tree indexes that are roughly sorted. When you insert a row whose key is bigger than every existing key (e.g., monotonically increasing IDs), the new row goes at the right edge of the tree — cheap, sequential disk write.

When you insert a row whose key is random, the database picks a random page in the tree to write to. Across millions of rows this means:

  • More page splits.
  • More random disk I/O.
  • Larger working set in RAM (the whole index is "hot," not just the tail).
  • Worse cache locality on reads of recent data.

For high-write tables (events, logs, transactions), the difference between v4 and v7 can be 2-5× insert throughput on a busy database.

Tested rule of thumb:

  • Auto-increment integer: fastest.
  • UUID v7 (time-ordered): ~5-15% slower than int.
  • UUID v4 (random): ~30-100% slower than int once the table grows past RAM.

If you are choosing UUIDs for a high-throughput Postgres / MySQL / SQL Server table, v7 is the modern best choice.


v7 vs ULID vs Snowflake — Are They the Same?

These all aim at "time-ordered, mostly unique 128-bit ID":

Format Bits Sortable Standardized Notes
UUID v7 128 Yes RFC 9562 (2024) The official one
ULID 128 Yes Community spec Same idea, different layout
Snowflake 64 Yes Twitter-internal, popularized Needs a coordinated worker ID
KSUID 160 Yes Segment.io Same idea, larger

UUID v7 is the winner because it is now a real standard, fits the existing UUID infrastructure (databases, JSON, validators), and does not require coordination between machines.


Code Examples

Python — UUID v4 and v7

import uuid

# v4 (random) — works on every Python version
print(uuid.uuid4())  # e.g. 550e8400-e29b-41d4-a716-446655440000

# v7 (time-ordered) — needs uuid7 from a library
# pip install uuid7
from uuid7 import uuid7
print(uuid7())       # e.g. 01890b6f-ce47-7c25-8a8d-3c8c7d3e9a4f

In Python 3.14+, uuid.uuid7() is built in.

JavaScript — UUID v4 and v7

// v4 — built into modern browsers and Node 19+
crypto.randomUUID();
// "550e8400-e29b-41d4-a716-446655440000"

// v7 — via the uuid npm package
import { v7 as uuidv7 } from "uuid";
uuidv7();
// "01890b6f-ce47-7c25-8a8d-3c8c7d3e9a4f"

PostgreSQL — generate UUID in SQL

-- v4: built-in since Postgres 13
SELECT gen_random_uuid();

-- v7: extension uuidv7 or function from the uuid-ossp / pg_uuidv7 extension
SELECT uuid_generate_v7();

SQL Server — UUID as primary key

-- v4-style (random, fragmented index — slow)
DEFAULT NEWID()

-- Time-ordered version (much faster index inserts)
DEFAULT NEWSEQUENTIALID()

When NOT to Use a UUID at All

UUIDs are 16 bytes vs 8 for a BIGINT. For internal database keys where you only need uniqueness within one DB, an auto-incrementing integer is:

  • Smaller (smaller indexes, less RAM).
  • Faster to compare (one CPU instruction vs string parsing).
  • Easier to read in logs.

Use UUIDs when:

  1. You need to generate IDs without talking to the database (offline-first apps, mobile, distributed systems).
  2. You expose IDs in URLs and don't want them sequential (privacy: ?invoice=1234 reveals you have 1234 invoices).
  3. You merge data from multiple sources without renumbering.

If none of those apply, an integer is probably better.


Frequently Asked Questions

Is UUID v4 truly unique?

For all practical purposes, yes. With 122 random bits there are 2¹²² ≈ 5×10³⁶ possibilities. Even at one billion UUIDs per second across all computers on Earth, you would need many trillions of years to expect a collision. The risk is essentially zero — unless your random number generator is broken.

Is UUID v7 backwards compatible with v4?

Yes. Both fit the same 36-character format. Any system that accepts UUIDs accepts v7. The version digit (the 7 after the second dash) signals the format, but parsers do not need special handling — it is still 16 bytes.

Is UUID v7 production-ready?

Yes. The RFC was finalized in May 2024 and major libraries (Python uuid7, JS uuid package v9+, Postgres extensions, .NET 9+) have stable support. Use it.

Should I switch existing v4 IDs to v7?

Not just for the sake of it. Mixing v4 (old) and v7 (new) records in the same table is fine — they are still all UUIDs. But you lose the index benefit until enough v7 records dominate.

How do I generate UUID v7 if my language doesn't support it yet?

Use a library or hand-roll: take the current Unix time in milliseconds (48 bits), set the version nibble to 7, and fill the rest with secure random bytes. Libraries are tested — prefer them.

Are UUIDs URL-safe?

The standard 36-character format with dashes is URL-safe. If you want shorter, encode the 16 bytes as base64url (22 characters) or base58. Some systems use a no-dash 32-character variant; both are valid.

Why is UUID v6 not on this list?

v6 exists — it is v1 re-ordered for sortability — but v7 is simpler and does not leak the MAC address. v7 supersedes v6 in practice; few libraries implement v6.

Can I use UUIDs as session tokens?

No. UUIDs (especially v4) are random but not designed for cryptographic secrecy. Use a dedicated CSPRNG token (e.g., 32 random bytes encoded as base64), or use your framework's session library.

How do I store UUIDs in the database?

  • Postgres: use the native uuid type (16 bytes). Don't store as a string — it's 2× the size and slower.
  • MySQL: use BINARY(16) for performance, or CHAR(36) if you prefer readability.
  • SQL Server: use UNIQUEIDENTIFIER (16 bytes).
  • MongoDB: use UUID (BSON binary subtype 4).

Does UUID v7 reveal when an object was created?

Yes — the first 48 bits are a millisecond Unix timestamp. If that's a privacy concern (publicly visible IDs that shouldn't leak creation time), use v4. For internal IDs and database keys, this is usually a feature, not a bug.


Try It Yourself

The UUID generator on this site runs entirely in your browser — generates v1, v4, and v7 UUIDs with one click. Nothing leaves your machine.

You can also experiment with both UUID generation and the resulting database insert behavior in the SQL playground (SQLite) and the Postgres playground (PGlite, real Postgres in your browser).

Want to learn more?

Explore free chapter-wise notes with quizzes and code playground

Prefer watching over reading?

Subscribe for free.

Subscribe on YouTube