What Is a UUID and When Should You Use One?
UUIDs appear in database rows, API responses, file names, and session tokens. They look like 550e8400-e29b-41d4-a716-446655440000 — 32 hex digits arranged in a specific pattern. Understanding what they are, how different versions are generated, and when they are the right choice will help you design better systems.
The UUID Format
A UUID (Universally Unique Identifier) is a 128-bit value, standardized by RFC 4122, typically displayed as 32 hexadecimal digits separated by hyphens into five groups: 8-4-4-4-12.
Format: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
M = version digit (1, 3, 4, 5, or 7)
N = variant bits (8, 9, a, or b in RFC 4122 UUIDs)
The total length as a string is 36 characters (32 hex digits + 4 hyphens). As raw bytes, a UUID is 16 bytes. This compact binary representation is important for database storage performance, which we will return to later.
The version digit (character 13 of the string) and variant bits (character 17) tell you how the UUID was generated. A UUID beginning with 550e8400-e29b-41d4-a716 has a 4 in position 13 (version 4, random) and a in position 17 (RFC 4122 variant).
UUID Versions: What Each One Does
Version 1: Time + MAC Address
UUID v1 combines a timestamp (nanoseconds since October 15, 1582 — the Gregorian calendar reform date) with the MAC address of the generating machine. The result is time-ordered, which can be useful for sorting. However, it exposes the generating machine's network address, which is a privacy concern. It is also not safe to generate multiple v1 UUIDs in rapid succession on the same machine without additional randomness, as the timestamp granularity may not be sufficient to guarantee uniqueness.
Version 3: Namespace + MD5 Hash
UUID v3 generates a deterministic UUID by hashing a namespace UUID and a name string together using MD5. Given the same namespace and name, you always get the same UUID. This is useful when you need a stable, reproducible identifier — for example, generating a UUID for a URL that should be the same every time you process that URL. Version 5 is preferred over v3 because it uses SHA-1 instead of the deprecated MD5.
Version 4: Random
UUID v4 is the most widely used version. It is generated from 122 bits of cryptographically secure random data (with 6 bits used for version and variant markers). There is no time component, no machine identifier — just randomness. This is what most frameworks generate when you call crypto.randomUUID() in a browser, uuid.uuid4() in Python, or UUID.randomUUID() in Java.
Version 5: Namespace + SHA-1 Hash
UUID v5 is like v3 but uses SHA-1 for hashing. It is the preferred choice when you need deterministic UUIDs. Standard namespace UUIDs are defined for DNS, URLs, OIDs, and X.500 names. For example, uuid5(DNS_NAMESPACE, "example.com") always produces the same UUID for that domain name, regardless of which machine or library generates it.
Version 7: Time-Ordered Random (New)
UUID v7 is a newer version (RFC 9562, 2024) that addresses one of v4's main database weaknesses. It encodes a Unix millisecond timestamp in the most significant bits, followed by random data. This makes UUIDs time-ordered — newer UUIDs sort after older ones — which is critical for B-tree index performance in databases. UUID v7 gives you the uniqueness of v4 with the sortability of sequential IDs.
The Collision Probability: How Unique Is "Practically Unique"?
UUID v4 has 122 bits of randomness, yielding about 5.3 × 10^36 possible values. To put the collision probability in perspective: if you generated one billion UUIDs per second for the entire age of the universe, the probability of a single collision would still be astronomically small — far below the probability of a hardware memory error corrupting your data.
For any practical application, UUID v4 collisions are not a real concern. The "universally unique" claim holds up. You do not need to query the database before inserting to check for conflicts.
Why UUIDs for Distributed Systems
The killer advantage of UUIDs is that they require no central coordination to generate. With sequential integer IDs, some centralized authority (a database auto-increment counter, a sequence service) must issue each new ID to prevent conflicts. This creates a bottleneck and a single point of failure in distributed architectures.
With UUIDs, any service, any machine, any client can independently generate an ID with negligible collision risk. A mobile app can generate a UUID for a new record before it even has network connectivity. Multiple microservices can generate IDs for records they will later merge into a shared database without any coordination. This property is invaluable in event-sourced systems, offline-first apps, and multi-region deployments.
The Database Performance Tradeoff
UUID v4's randomness is also its main weakness in relational databases. Database B-tree indexes perform best when new entries are inserted in order — sequential IDs achieve this naturally. Random UUIDs cause "index fragmentation": each new insert goes to a random position in the index, requiring page splits and cache misses that degrade write performance significantly at scale.
Benchmarks on large datasets consistently show that random UUID primary keys produce 2–5x worse write throughput than sequential integer keys under heavy insert load. Read performance on UUID-keyed tables also suffers because related records are scattered across disk pages rather than clustered together.
Generate UUIDs in any version
Generate v1, v4, v5, or v7 UUIDs instantly, in bulk, with options for uppercase, lowercase, and braces format.
ULID: An Alternative Worth Knowing
ULID (Universally Unique Lexicographically Sortable Identifier) is an alternative to UUID that aims to combine the best properties of both UUID and sequential IDs. A ULID is 128 bits: the upper 48 bits encode a millisecond timestamp, and the lower 80 bits are random. It is encoded in Base32 rather than hex, producing a 26-character string like 01ARZ3NDEKTSV4RRFFQ69G5FAV.
ULIDs are lexicographically sortable (newer ULIDs sort after older ones as strings), monotonically increasing within the same millisecond (with optional monotonic mode), and URL-safe. They solve the database index fragmentation problem while maintaining decentralized generation. UUID v7 has largely converged on the same design philosophy with the advantage of standardization; if your stack supports v7, that is the modern choice.
Practical Recommendations for Databases
- High-insert tables where performance matters: Use UUID v7 or ULID — both are time-ordered and avoid index fragmentation. PostgreSQL and MySQL both support storing UUIDs efficiently as binary(16) to halve storage compared to varchar(36).
- Distributed systems where records are created independently: UUID v4 is fine if insert volume is moderate. Switch to v7 if you experience index performance issues at scale.
- Deterministic identifiers (same input → same ID): Use UUID v5 with an appropriate namespace.
- Simple monolithic applications with low write volume: Sequential integers (BIGINT AUTO_INCREMENT) are simpler, smaller (8 bytes vs 16), and have no index fragmentation. Use them unless you have a specific reason for UUIDs.
- Never expose sequential integer IDs in public-facing URLs if you want to prevent enumeration attacks (e.g., iterating through user IDs). UUIDs solve this problem by design.
The Bottom Line
UUIDs are the right choice when you need globally unique identifiers without central coordination — distributed systems, offline-first apps, public-facing APIs where sequential IDs would expose enumeration opportunities, and any system that merges data from multiple sources. For pure database performance in a centralized system with high insert volume, sequential integer IDs still have the edge. UUID v7 and ULID bridge the gap for cases where you need both.
Try the UUID Generator
Generate single or bulk UUIDs in any version, with one-click copy and format options.