DEV Community

Snappy Tools
Snappy Tools

Posted on

UUID Best Practices: v4, v7, and When You Should Use Each

UUIDs (Universally Unique Identifiers) are everywhere — database primary keys, request IDs, session tokens, file names. Most developers reach for UUID v4 by default, but UUID v7 is newer and better for many use cases. Here's what's changed and how to choose.

What makes a UUID unique

A UUID is 128 bits presented in a standardised format: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx. The M character indicates the version (1–8), N indicates the variant.

The guarantee: the probability of generating a duplicate UUID v4 is astronomically low. With 122 random bits, you'd need to generate about 2.7 quintillion UUIDs before having a 50% chance of a collision. For practical purposes, they're unique.

UUID v4: pure randomness

UUID v4 is 122 bits of cryptographically random data:

550e8400-e29b-41d4-a716-446655440000
         ^
         "4" = version 4
Enter fullscreen mode Exit fullscreen mode

When to use v4:

  • Session tokens and temporary identifiers
  • File names for uploads
  • Any ID where sorting order is irrelevant
  • IDs generated on the client side

The problem with v4 in databases: UUID v4 values are completely random. When used as primary keys in indexed databases (like PostgreSQL or MySQL), inserts arrive in random index positions, causing index fragmentation over time. On large tables (millions+ rows), this degrades insert performance measurably. Reads are also less efficient since related rows are scattered throughout the index.

UUID v7: random but time-ordered

UUID v7 was standardised in 2024 (RFC 9562). It encodes a Unix millisecond timestamp in the first 48 bits, followed by random bits:

018e3b5c-a4b2-7b3f-9c4a-2d8f1e0a5b6c
^^^^^^^^^
timestamp (48 bits, millisecond precision)
Enter fullscreen mode Exit fullscreen mode

When to use v7:

  • Database primary keys — especially beneficial in large tables
  • Event IDs and log entries where chronological order matters
  • Any ID that benefits from sequential ordering

Why it's better for databases: UUID v7 IDs are roughly time-ordered. New inserts go at the end of the B-tree index rather than random positions, eliminating index fragmentation. PostgreSQL and MySQL both benefit significantly — insert performance on indexed UUID columns approaches sequential integer performance.

UUID v1: avoid in most cases

UUID v1 encodes the MAC address of the generating machine and a timestamp. The MAC address is a privacy concern (fingerprints the machine), and the timestamp encoding is unusual (100-nanosecond intervals since 1582). UUID v7 supersedes v1 for time-based use cases.

UUID v5: deterministic from a namespace

UUID v5 is a deterministic UUID generated from a namespace UUID + a name string via SHA-1:

// Always produces the same UUID for the same inputs
uuidv5('example.com', uuidv5.DNS)  // deterministic
Enter fullscreen mode Exit fullscreen mode

When to use v5:

  • Stable IDs for the same entity across systems
  • Deduplicated event IDs (same event inputs → same UUID → idempotent processing)
  • URL-safe identifiers derived from content

Should you use UUIDs at all?

Arguments for UUIDs:

  • No centralised ID generation — any service can generate unique IDs without coordination
  • IDs are safe to expose in URLs (unlike sequential integers, which reveal record count)
  • Easy to merge data from multiple sources

Arguments against:

  • 16 bytes vs 4 bytes for a 32-bit integer — 4× storage cost per key, with cascading costs in foreign keys and indexes
  • Less readable than sequential integers in logs and debugging
  • Slight performance overhead compared to sequential integers

When integers are fine: small-to-medium single-database applications where you control all ID generation and don't expose IDs externally.

When UUIDs are worth it: distributed systems, multi-tenant databases, any situation where IDs may be generated by clients, or where exposing sequential IDs is a security concern.

Generating UUIDs

In JavaScript:

// Built-in (Node.js 15+, all modern browsers)
crypto.randomUUID()  // UUID v4
Enter fullscreen mode Exit fullscreen mode

For UUID v7 in JavaScript, use the uuid package:

import { v7 as uuidv7 } from 'uuid';
uuidv7()  // UUID v7, time-ordered
Enter fullscreen mode Exit fullscreen mode

In Python:

import uuid
str(uuid.uuid4())  # v4
Enter fullscreen mode Exit fullscreen mode

UUID v7 in Python requires the uuid7 package as of 2024 (not in the standard library yet).

For quick generation without writing code, the UUID Generator generates UUID v4 and v7 in bulk and also decodes existing UUIDs — useful for inspecting the timestamp encoded in a v7 UUID.

Storing UUIDs efficiently

PostgreSQL: use the native uuid type — it stores UUIDs as 16 bytes, not as a 36-character string.

MySQL/MariaDB: MySQL has a uuid function but stores in text by default. For large tables, store as BINARY(16) and use UUID_TO_BIN(uuid, 1) (the 1 flag reorders bytes for better index performance with v1 UUIDs — use UUID_TO_BIN(uuid, 0) for v7 which is already time-ordered).

MongoDB: native Binary type or use UUID v7 as the _id for time-ordered inserts.


The migration from v4 to v7 for database primary keys is one of the highest-value, lowest-effort performance improvements available for UUID-heavy workloads. If you're starting a new project that uses UUIDs as primary keys, default to v7. For everything else — tokens, session IDs, client-generated IDs — v4 remains the right choice.

Top comments (0)