
You see them everywhere once you start looking: in database rows, API responses, log files, file names, browser storage. They look like 550e8400-e29b-41d4-a716-446655440000. You know they are identifiers, but not why they are formatted that way, what the different versions mean, or why most applications generate one version and almost never touch the others.
The UUID generator produces a version 4 UUID in one click, ready to copy. This guide covers what the format contains, how each version works, when to choose one over another, and the practical considerations for using UUIDs in databases and APIs.
What Is a UUID?
A UUID (Universally Unique Identifier) is a 128-bit value. Those 128 bits are represented as 32 hexadecimal digits arranged in a fixed pattern: five groups separated by hyphens in an 8-4-4-4-12 structure. The example from RFC 4122 itself:
550e8400-e29b-41d4-a716-446655440000
The design goal is coordination-free uniqueness. Any machine, at any time, can generate a UUID without registering with a central authority, and the result will be unique across all machines and all time. This is what makes UUIDs practical for distributed systems: generating a new record ID does not require a database round-trip to get the next sequence value.
RFC 4122, published by the IETF in 2005, defines the format, the five version types, and the bit-level layout. A follow-up standard, RFC 9562, published in 2024, added UUID versions 6, 7, and 8 and explicitly defined the nil and max UUIDs. Most current systems implement RFC 4122 versions, though UUID7 is gaining adoption for its time-sortable property.
The Five UUID Versions
RFC 4122 defines five UUID versions. Every version uses the same 128-bit output format but generates the value differently.
| Version | Generation Basis | Deterministic? | Privacy-safe? | Primary Use |
|---|---|---|---|---|
| v1 | Timestamp + MAC address | No | No | Legacy systems, time-ordered IDs |
| v2 | Timestamp + POSIX UID | No | No | DCE Security (rarely used) |
| v3 | MD5(namespace + name) | Yes | Yes | Namespace hashing, legacy |
| v4 | Random data | No | Yes | General use (dominant choice) |
| v5 | SHA-1(namespace + name) | Yes | Yes | Namespace hashing, preferred |
Version 2 appears in older distributed computing contexts (specifically DCE/RPC systems) and is rarely seen in modern application development. The practical decision for new applications is between v1, v4, and v5.
Why Version 4 Is the Standard Choice
Version 4 UUIDs are random. The generator takes 122 bits of random data and sets the remaining 6 bits to the version marker (4) and variant marker (RFC 4122 variant) specified by the standard. That is the entire process. No clock. No network interface lookup. No coordination with other processes.
The 6 bits reserved for markers are where a common misconception lives. A UUID4 has 128 bits total but only 122 bits of actual randomness. Looking at the pattern:
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
^ always 4 (version)
^ always 8, 9, a, or b (variant)
Every position marked x is genuinely random. The version digit in position 13 of the hex string is always 4. The first hex digit of the fourth group is always 8, 9, a, or b because those four values encode the RFC 4122 variant in binary (10xx). Every other digit is random.
This simplicity is why v4 dominates. Standard libraries handle it with a single call: crypto.randomUUID() in Node.js 14.17+ and modern browsers, uuid.uuid4() in Python, uuid.New() in Go. Frameworks that need a unique identifier for any purpose (session tokens, record IDs, idempotency keys) reach for UUID4 without a second thought.
What Is the Difference Between a UUID and a GUID?
UUID and GUID are the same thing. GUID (Globally Unique Identifier) is Microsoft's term, used throughout Windows, COM, OLE, and .NET documentation. UUID is the IETF term from RFC 4122. The format, the version structure, and the byte layout are identical.
Microsoft's CoCreateGuid() function in Windows produces RFC 4122-compatible output. When GUIDs appear in Windows-style documentation surrounded by curly braces, like {550e8400-e29b-41d4-a716-446655440000}, the braces are a display convention for the Windows registry and COM interfaces. The braces are not part of the value itself and should be stripped when using the ID in a database or API.
The terms appear in the same codebases when teams mix Windows-origin components with cross-platform code. Treating them as interchangeable is correct.
How Low Is the Collision Risk?
Generating 1 billion version 4 UUIDs per second continuously would require approximately 85 years before the probability of any two UUIDs matching reached 50%. The space has 2^122 possible values, roughly 5.3 × 10^36. The birthday problem says collision probability grows with the square root of the number of items relative to the space size. Applied to 2^122, the number of UUIDs needed to reach 50% collision probability is approximately 2.7 × 10^18.
In practical terms: a system generating 1 million UUIDs per day would need 7.4 trillion years to accumulate enough UUIDs for a 50% collision chance. The age of the universe is about 14 billion years.
This is why production systems do not build collision detection into UUID generation. The actual risk of a UUID collision in any real application is many orders of magnitude lower than the risk of a disk write failure silently corrupting the same data. Teams that add uniqueness constraints on UUID columns do so for foreign key integrity guarantees, not because they expect collisions.
When to Use Version 5 Instead of Version 4
Version 5 is deterministic: given the same namespace UUID and the same name string, it always produces the same output UUID. The generation process concatenates the namespace bytes and the name bytes, hashes them with SHA-1, then truncates and formats the result as a 128-bit UUID with the version 5 marker.
The use case is stable identifiers for named resources. If admin@example.com should always have the same user UUID whether the ID is generated today, next year, or on a different server, use UUID5 with a fixed namespace UUID and the email address as the name. Any system that knows the namespace and the name can independently compute the same UUID without querying a database.
RFC 4122 defines standard namespace UUIDs for DNS names, URLs, ISO OIDs, and X.500 names. You can also generate your own namespace UUID once (using UUID4) and treat it as a permanent constant for your application.
Version 3 does the same thing with MD5 instead of SHA-1. Since MD5 is cryptographically broken, prefer version 5 for any new code. The determinism property is identical; only the hash function differs.
The Nil UUID and Max UUID
The nil UUID is all zeros: 00000000-0000-0000-0000-000000000000. RFC 4122 defines it as the UUID representing the absence of a UUID, used the same way null represents the absence of a value in most type systems. Some APIs return the nil UUID when a query finds no matching resource rather than returning null or an error response.
RFC 9562 (2024) explicitly defines the max UUID as all F's: ffffffff-ffff-ffff-ffff-ffffffffffff. It is used as a sentinel value in range queries, similar to how INT_MAX is used in numeric contexts.
RFC 9562 also defines UUID version 7, which was absent from RFC 4122. Version 7 encodes a Unix millisecond timestamp in the most significant bits followed by random data in the remaining bits. This makes UUID7 values time-sortable: newer values are always lexicographically greater than older values. This property solves the B-tree fragmentation problem that UUID4 causes in database indexes.
How to Generate a UUID
Browser (no code required): Open the UUID generator and click Generate. The tool uses crypto.randomUUID() from the Web Crypto API, which draws entropy from hardware-level sources. No account, no installation.
JavaScript (browser and Node.js 14.17+):
const id = crypto.randomUUID();
// "550e8400-e29b-41d4-a716-446655440000"
Node.js with the uuid package (for older environments or v5 support):
import { v4 as uuidv4, v5 as uuidv5 } from 'uuid';
const id = uuidv4();
// Random UUID4
const stableId = uuidv5('admin@example.com', uuidv5.URL);
// Same UUID every time for the same email + namespace
Python:
import uuid
id = str(uuid.uuid4())
# "550e8400-e29b-41d4-a716-446655440000"
stable_id = str(uuid.uuid5(uuid.NAMESPACE_URL, 'admin@example.com'))
# Deterministic UUID5
PostgreSQL (13+):
SELECT gen_random_uuid();
-- Returns a UUID4
MySQL:
SELECT UUID();
-- Returns a UUID1 (timestamp-based, not random)
The MySQL UUID() function generates version 1, not version 4. Version 1 UUIDs embed the server's MAC address and a timestamp. If you use UUID() to generate primary keys in MySQL and privacy matters, be aware that these IDs reveal your database server's network interface address. Generate UUID4 values in your application layer and pass them to MySQL rather than relying on the database function.

UUID as a Database Primary Key
UUIDs work well as primary keys in distributed systems. Multiple application servers can insert rows simultaneously without coordinating on which ID to use next. Auto-increment integers require a single sequence source, which becomes a bottleneck under high concurrent write load or when merging records from separate databases.
The tradeoff is write performance on large tables. PostgreSQL and MySQL both use B-tree indexes by default. Sequential integers always append to the rightmost index page. Random UUID4 values insert at arbitrary positions throughout the index, causing frequent page splits and rebalancing. On tables with tens of millions of rows, this fragmentation slows write operations measurably.
The practical solutions: use UUID7 (time-sortable, no fragmentation), use PostgreSQL's native uuid column type with the uuid-ossp extension's uuid_generate_v1mc() function (which generates a version 1 UUID with a random node ID instead of the actual MAC address, giving you time-sortable values without the privacy issue), or maintain sequential integer primary keys internally and expose application-layer UUIDs for external API responses. A 36-character UUID string can also be stored as 24-character base64 in space-constrained contexts using the base64 encoder and decoder.
Storing and Validating UUIDs
UUIDs are commonly stored as 36-character strings (VARCHAR(36) including hyphens). PostgreSQL has a native uuid column type that stores 16 bytes internally while accepting and returning the standard string format. This type validates format automatically and indexes efficiently. MySQL lacks a native UUID type but accepts BINARY(16) with manual conversion, saving half the storage compared to text.
To validate a UUID string format (not uniqueness, just well-formedness), a standard regex works across languages:
^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
This matches any RFC 4122 UUID v1 through v5 in lowercase. UUIDs are case-insensitive by specification: 550E8400 and 550e8400 identify the same value. The convention is lowercase, but APIs that return uppercase UUIDs are fully RFC-compliant.
When building test data that includes UUIDs, the fake data for testing guide covers how to generate realistic-looking test datasets where UUIDs appear in the expected format alongside other fields. The hash generator handles cases where you need a one-way fingerprint of data rather than a unique identifier. Both UUIDs and hashes appear as fixed-length hex strings in developer workflows but serve entirely different purposes.
The developer tools section has the UUID generator alongside the base64 encoder, hash generator, and other utilities for common development tasks.
