Tutorial7 min read

How to Generate UUIDs: v4, v7, and When to Use Each

UUIDs come in seven versions, each with different trade-offs around uniqueness, ordering, and database performance. Learn when v4 is the right call, when v7 wins, and how to generate them safely.

UUIDs are the closest thing computing has to a guaranteed-unique identifier. Generate one on your laptop, generate one in a data center on the other side of the world, and the odds of a collision are vanishingly small. They show up in databases, distributed systems, OAuth tokens, file paths — everywhere a sequential ID would create coordination problems. Here's the practical guide.

What Is a UUID?

A UUID (Universally Unique Identifier), also called a GUID (Globally Unique Identifier — same thing, Microsoft's name), is a 128-bit value usually written as 32 hexadecimal characters in five groups separated by hyphens:

550e8400-e29b-41d4-a716-446655440000

The format is defined by RFC 4122 (and updated by RFC 9562 in 2024). The 128 bits give you 2^128 possible values — roughly 3.4 × 10^38 — large enough that randomly generated UUIDs almost never collide.

The Different Versions

Not all UUIDs are random. The format reserves four bits to indicate the version, which tells you how the UUID was generated.

Version Source Use Case
v1 Timestamp + MAC address Time-ordered, leaks the host's MAC
v3 MD5 of namespace + name Deterministic from inputs
v4 Random / pseudorandom General-purpose unique IDs
v5 SHA-1 of namespace + name Deterministic, more secure than v3
v6 Reordered v1 (sortable) Time-ordered, no MAC leak
v7 Unix ms timestamp + random Time-ordered, database-friendly
v8 Custom / vendor-defined Reserved for application-specific schemes

For most applications today, you want v4 (random) or v7 (time-ordered for database keys).

When to Use UUID v4

v4 is the default for a reason: it's purely random, requires no coordination, and reveals nothing about its origin.

f47ac10b-58cc-4372-a567-0e02b2c3d479

Use v4 when:

  • You need a non-guessable token (session IDs, share links)
  • You want to prevent ID enumeration attacks (don't expose /users/1, /users/2)
  • You don't care about ordering
  • You don't need to derive the ID from inputs

The downside of v4 in databases is insertion locality. Random UUIDs land in random index pages, causing index churn. For a high-write table, this can hurt performance noticeably compared to sequential IDs.

When to Use UUID v7

v7 is new (standardized in RFC 9562 in 2024) and solves the insertion locality problem. The first 48 bits are a Unix timestamp in milliseconds, followed by random bits:

018d3e5d-3a45-7000-8000-000000000000
└──── timestamp ────┘└── version + random ──┘

Two UUIDs generated a millisecond apart sort sequentially. They still feel random — adjacent IDs aren't guessable — but inserts cluster in the same index pages.

Use v7 when:

  • The UUID will be a primary key on a high-write table
  • You want to sort records by creation time without an extra timestamp column
  • You're using PostgreSQL, MySQL, or any database where index locality matters

Most languages now have v7 support — uuidv7 in Node.js (uuid package v9+), uuid_v7 in Rust, Python's uuid7 (third-party), Go's github.com/google/uuid.

When to Use UUID v3 or v5

v3 and v5 are deterministic: the same inputs always produce the same UUID. They take a "namespace" UUID and a name string, then hash them.

v5(namespace=DNS, name="example.com") = cfbff0d1-9375-5685-968a-48ce8b50e3e0

Useful for:

  • Deduplicating items where you can derive a stable input (e.g., a UUID per email address)
  • Generating consistent IDs across distributed systems without coordination
  • Migrating string keys to UUID columns deterministically

v5 (SHA-1) is preferred over v3 (MD5) — MD5 is broken for security purposes, though for non-cryptographic deduplication either works.

Why Not Just Use Auto-Increment?

The classic alternative is a sequential integer (1, 2, 3...). It's smaller (8 bytes vs 16 for a UUID) and indexes are denser. Trade-offs:

Concern Auto-Increment UUID
Storage 8 bytes 16 bytes
Index efficiency Best (sequential) Poor (v4) / Good (v7)
Distributed generation Requires coordination None needed
Hides record count Exposes (/users/8421) Hides
Mergeable across DBs Conflicts No conflicts
URL aesthetics Short and clean Long

For internal IDs in a single-DB monolith, auto-increment is fine. For distributed systems, multi-tenant apps, public-facing identifiers, or anything you'll later need to merge from multiple sources, UUIDs win.

How to Generate UUIDs Online

Use DevZone's UUID Generator to generate one or many UUIDs of any version:

  1. Pick the version (v4 for general use, v7 for database keys).
  2. Choose how many to generate (1 to 1000).
  3. Copy the result, or download as a .txt or .json file.

The generation runs in your browser using the Web Crypto API — no UUIDs are ever sent to a server.

Generating in Code

JavaScript / Node.js (built-in):

import { randomUUID } from "crypto";
const id = randomUUID();          // v4

For v7, use the uuid package:

import { v7 as uuidv7 } from "uuid";
const id = uuidv7();

Python:

import uuid
id_v4 = str(uuid.uuid4())
# v7 needs the third-party `uuid7` package or Python 3.13+

Go:

import "github.com/google/uuid"
id := uuid.New()                  // v4
id7, _ := uuid.NewV7()

PostgreSQL:

-- v4 via pgcrypto extension
SELECT gen_random_uuid();

-- v7 via uuid-osp or custom function

Rust:

use uuid::Uuid;
let id_v4 = Uuid::new_v4();
let id_v7 = Uuid::now_v7();

Collision Probability

The number of v4 UUIDs you'd need to generate to reach a 50% chance of a collision is about 2.71 × 10^18. To put that in perspective:

  • Generating one billion UUIDs per second
  • Continuously for 100 years
  • ...gives you about a 50% chance of one collision

In practice, treat v4 UUIDs as guaranteed unique. The bigger risk is buggy code that generates UUIDs from a weak random source — Math.random() in old JavaScript, random.random() seeded with a constant in Python tests, etc. Always use a cryptographic RNG.

FAQ

Are UUIDs case-sensitive?

No. Both 550e8400-e29b-41d4-a716-446655440000 and 550E8400-E29B-41D4-A716-446655440000 are the same UUID. Most libraries emit lowercase by convention. Microsoft tooling sometimes prefers uppercase.

What's a "nil" UUID?

00000000-0000-0000-0000-000000000000 — the all-zeros UUID, used as a placeholder meaning "no UUID assigned." It's officially defined in the spec, so you can match against it without ambiguity. There's also a "max" UUID (ffffffff-ffff-ffff-ffff-ffffffffffff) added in RFC 9562.

Can a UUID start with a number?

Yes — UUIDs are hex characters, so they can start with 0–9 or a–f. The version digit at position 14 (the start of the third group) is what tells you the version: 4 for v4, 7 for v7, etc.

Can I shorten a UUID?

You can re-encode the 128 bits in base64 (22 characters) or base58 (around 22 characters) to shorten the string while preserving the value. ULID and KSUID are alternative formats designed to be shorter and time-sortable from the start. They're not interoperable with UUIDs but solve similar problems.

Should I use UUID strings or binary in the database?

Postgres has a native uuid type that stores it as 16 bytes — use it. MySQL stores UUIDs as 36-character strings (CHAR(36) or BINARY(16) if you pack manually). Storing as a string costs 2.25× the space of binary and makes indexes larger. If your DB has a native UUID type, use it.

Try the tools