UUID stands for Universally Unique Identifier. It is a 128-bit value, typically written as 32 hexadecimal characters in five groups separated by hyphens: 550e8400-e29b-41d4-a716-446655440000. The design goal is that independently generated UUIDs should never collide — no central authority is needed to coordinate the assignment of unique identifiers.
The UUID Format
The canonical UUID format is eight hexadecimal digits, a hyphen, four digits, a hyphen, four digits, a hyphen, four digits, a hyphen, twelve digits: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx. The M position indicates the version (1–8) and the N position indicates the variant (most UUIDs use variant 2, indicated by a leading 1, 0, or c bit pattern in N).
UUID Versions Explained
There are several UUID versions, each with a different generation strategy. Version 1 uses the current timestamp and the MAC address of the generating machine. This produces sortable UUIDs but leaks the machine identity and exact creation time, which is a privacy concern. Version 4 is generated from cryptographically random bits — it carries no information about when or where it was generated, just 122 bits of randomness. Version 5 is a deterministic UUID produced by hashing a namespace and a name with SHA-1, useful when you want the same input to always produce the same UUID. Version 7, introduced in 2024, combines a millisecond-precision timestamp with random bits, giving time-ordered UUIDs that are better for database indexing.
- v1: timestamp + MAC address. Sortable but exposes metadata.
- v4: random. Best for most uses — no metadata leakage.
- v5: SHA-1 hash of namespace + name. Deterministic.
- v7: timestamp prefix + random suffix. Time-ordered, database-friendly.
UUID as a Primary Key
Using UUIDs as database primary keys has significant advantages: multiple services can generate keys independently without coordination, keys can be assigned before a database insert, and keys do not expose row counts or insertion order to clients. These properties make UUIDs attractive for distributed systems and for APIs where you do not want to leak how many records exist.
The main downside is index performance. B-tree indexes in relational databases perform best when new keys are sequential — each new key is appended at the right end of the index. Random v4 UUIDs scatter inserts across the entire index, causing page splits and fragmenting the index. For high-write tables, this is a real performance cost. UUID v7, which starts with a timestamp, largely solves this problem while keeping the coordination-free benefits of UUIDs.
Alternatives to UUID
ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit identifier that encodes a millisecond timestamp in its first 48 bits and random bits in its remaining 80 bits, represented in a 26-character base-32 string. It sorts lexicographically by creation time and is URL-safe. CUID2 and NanoID are shorter alternatives designed for different trade-offs. Auto-increment integers remain the right choice for single-node databases where insert performance matters most and exposing row counts is not a concern.
Are UUIDs Safe to Expose?
v4 UUIDs are safe to expose in URLs and API responses — they leak no information about creation time or machine identity, and with 122 bits of randomness, guessing a valid UUID is not feasible. However, do not rely on UUIDs as access control. A UUID in a URL is an identifier, not a secret. If a user should not be able to access a resource by guessing or enumerating IDs, enforce that with authorization checks on the server, not by making the ID hard to guess.