A UUID (Universally Unique Identifier) is a 128-bit value used to uniquely identify information in computer systems. Standardized by RFC 4122 and later updated by RFC 9562, UUIDs are designed to be globally unique without requiring a central registration authority. This makes them invaluable in distributed computing where multiple systems need to generate identifiers independently and still guarantee uniqueness.
The concept of UUIDs emerged from the need to identify objects across networked systems. Originally developed by Apollo Computer for their Network Computing System in the 1980s, UUIDs were later adopted by the Open Software Foundation (OSF) as part of the Distributed Computing Environment (DCE). Today, UUIDs are ubiquitous -- they appear in database primary keys, API responses, file systems, messaging queues, and virtually every distributed system you will encounter.
A typical UUID looks like this:
550e8400-e29b-41d4-a716-446655440000
That string of hexadecimal digits, grouped by hyphens, represents a 128-bit number. There are approximately 3.4 x 10^38 possible UUID values -- a number so astronomically large that if every person on Earth generated a billion UUIDs per second, it would take trillions of years to exhaust the space. This near-infinite keyspace is what makes UUIDs practical for decentralized identifier generation.
UUIDs are also known by other names in different ecosystems. Microsoft calls them GUIDs (Globally Unique Identifiers), and you will sometimes see the term "unique ID" used informally. Regardless of the terminology, the underlying concept and format are the same.
A UUID is represented as a 32-character hexadecimal string, divided into five groups separated by hyphens in the pattern 8-4-4-4-12. This gives the familiar 36-character format (including hyphens):
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
| | | | | | | |
| time_low | | | | | node (48 bits)
| | time_mid | | clock_seq (14 bits)
| | | version | variant (2 bits)
| | | (4 bits)|
+------+----+--------+---+--------------+
8 4 4 4 12 = 32 hex chars
The 128 bits of a UUID are organized into specific fields, though the meaning of each field varies by version:
10 in binary for RFC 4122 UUIDs). The remaining 14 bits are version-specific data.Two fields are present in every UUID regardless of version:
4. For UUID v7, it is 7.8, 9, a, or b (binary 10xx).
You can always identify a UUID's version by looking at the 13th hex character. A UUID starting with xxxxxxxx-xxxx-4xxx is always a v4 UUID. Similarly, xxxxxxxx-xxxx-7xxx is always v7.
While UUIDs are displayed as hexadecimal strings, they are stored and transmitted as 128-bit (16-byte) binary values. The canonical string representation is simply a human-readable encoding. When storing UUIDs in databases, the binary form (BINARY(16) or a native UUID type) is more storage-efficient than the string form (CHAR(36)).
There are several UUID versions, each using a different algorithm to generate the 128-bit value. The version you choose affects the properties of the generated UUIDs -- whether they contain timestamps, are sortable, or are purely random. Here is a comprehensive overview of each version.
UUID v1 combines a 60-bit timestamp (measured in 100-nanosecond intervals since October 15, 1582) with a 48-bit node identifier, typically the machine's MAC address. A 14-bit clock sequence prevents duplicates when the clock is adjusted backward or the node ID changes.
Pros: Time-ordered (roughly), embeds creation time, low collision risk across machines.
Cons: Leaks the machine's MAC address (privacy concern), not truly random, can be predicted. The embedded MAC address reveals information about the generating host, which is a security risk in many applications.
# Example UUID v1
f47ac10b-58cc-1de5-97d8-0242ac130003
^
version = 1
UUID v3 generates a deterministic UUID by computing the MD5 hash of a namespace UUID concatenated with a name string. Given the same namespace and name, UUID v3 always produces the same UUID. This is useful when you need reproducible identifiers derived from meaningful inputs.
RFC 4122 defines four standard namespace UUIDs: DNS (6ba7b810-9dad-11d1-80b4-00c04fd430c8), URL, OID, and X.500. For example, generating a UUID v3 from the DNS namespace and the name "example.com" always yields the same UUID.
Pros: Deterministic and reproducible.
Cons: MD5 is cryptographically broken; prefer UUID v5 (SHA-1) for new applications.
UUID v4 is the most widely used version. It generates 122 random bits (the remaining 6 bits are used for the version and variant fields) using a cryptographically secure random number generator. UUID v4 values have no inherent meaning -- they are pure randomness formatted as a UUID.
Pros: Simple to generate, no privacy leakage, no state required, extremely low collision probability.
Cons: Not time-sortable, causes B-tree index fragmentation in databases, no embedded metadata.
# Example UUID v4
f47b3f6e-2c84-4e5a-b9d7-8a1c9f3e2d4b
^
version = 4
UUID v5 is identical in concept to UUID v3, but uses SHA-1 instead of MD5 for hashing. Like v3, it is deterministic -- the same namespace and name always produce the same UUID. UUID v5 is preferred over v3 for new applications because SHA-1 is a stronger hash function (though also deprecated for cryptographic purposes, it is sufficient for identifier generation).
Use case: Generating stable identifiers from URLs, domain names, or other string inputs without requiring a central registry.
UUID v7 is defined in RFC 9562 (2024) and addresses the primary weakness of UUID v4 for database use: lack of time ordering. UUID v7 embeds a 48-bit Unix timestamp in milliseconds in the most significant bits, followed by 74 random bits (after accounting for version and variant). This makes UUID v7 values lexicographically sortable by creation time.
Pros: Time-sortable (ideal for database primary keys), maintains insertion order, avoids B-tree fragmentation, embeds creation time, still has 74 bits of randomness for uniqueness.
Cons: Slightly more complex to generate, leaks approximate creation time (which may or may not be desirable).
# Example UUID v7
0190a6e5-7b3c-7f2e-8a1b-4c5d6e7f8a9b
^
version = 7
# Structure:
# 0190a6e5-7b3c = Unix timestamp (ms) in first 48 bits
# 7 = version (7)
# f2e = random
# 8a1b-4c5d... = variant + random
UUID v7 is rapidly becoming the recommended choice for new applications that need database-friendly unique identifiers. It combines the global uniqueness of UUIDs with the sortability that databases need for efficient indexing.
| Version | Algorithm | Sortable | Deterministic | Recommended |
|---|---|---|---|---|
| v1 | Timestamp + MAC | Partially | No | Legacy only |
| v3 | MD5 hash | No | Yes | Use v5 instead |
| v4 | Random | No | No | General purpose |
| v5 | SHA-1 hash | No | Yes | Name-based IDs |
| v7 | Timestamp + Random | Yes | No | Database keys |
UUID v4 is the most commonly generated version and relies entirely on randomness. Understanding how it works under the hood helps appreciate both its simplicity and its security properties.
Generating a UUID v4 requires just three steps:
0100 (binary), which makes the 13th hex character 4.10 (binary), which constrains the 17th hex character to 8, 9, a, or b.
In modern browsers and Node.js, the Web Crypto API provides crypto.getRandomValues(), which draws randomness from the operating system's CSPRNG. Here is how UUID v4 generation works in JavaScript:
function generateUUIDv4() {
// Step 1: Generate 16 random bytes
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
// Step 2: Set version to 4 (0100 in binary)
bytes[6] = (bytes[6] & 0x0f) | 0x40;
// Step 3: Set variant to RFC 4122 (10xx in binary)
bytes[8] = (bytes[8] & 0x3f) | 0x80;
// Convert to hex string with hyphens
const hex = Array.from(bytes)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return [
hex.slice(0, 8),
hex.slice(8, 12),
hex.slice(12, 16),
hex.slice(16, 20),
hex.slice(20, 32)
].join('-');
}
Modern browsers also provide crypto.randomUUID(), a built-in method that returns a UUID v4 string directly. Under the hood, it performs the same steps but is implemented natively for maximum performance and security:
// Modern browsers and Node.js 19+
const uuid = crypto.randomUUID();
// "3b241101-e2bb-4d7b-8b11-0f6f29e45bf5"
The security and uniqueness of UUID v4 depends entirely on the quality of the random number generator. A CSPRNG (Cryptographically Secure Pseudo-Random Number Generator) provides several guarantees:
Never use Math.random() to generate UUIDs. Math.random() is not cryptographically secure, uses a predictable algorithm (typically xorshift128+ with a 128-bit state), and can produce collisions far more easily than a proper CSPRNG.
A common concern with random UUIDs is the possibility of generating two identical values -- a "collision." Understanding the mathematics behind collision probability reveals just how vanishingly small this risk actually is.
The collision probability for UUIDs follows the same mathematics as the birthday problem: in a group of 23 people, there is a greater than 50% chance that two people share the same birthday. This seems surprising because there are 365 possible birthdays, but collisions become likely much sooner than intuition suggests.
The general formula for the probability of at least one collision when generating n items from a space of N possibilities is approximated by:
P(collision) ~ 1 - e^(-n^2 / (2 * N))
For 50% probability:
n ~ sqrt(2 * N * ln(2)) ~ 1.177 * sqrt(N)
UUID v4 has 122 random bits, giving N = 2^122 ~ 5.317 x 10^36 possible values. Plugging into the birthday paradox formula:
For 50% collision probability:
n ~ 1.177 * sqrt(2^122)
n ~ 1.177 * 2^61
n ~ 2.71 x 10^18 (2.71 quintillion UUIDs)
For a 1 in a billion (10^-9) collision probability:
n ~ sqrt(2 * 2^122 * 10^-9)
n ~ 3.26 x 10^13 (32.6 trillion UUIDs)
To put this in perspective: if you generated 1 billion UUIDs per second, it would take approximately 86 years to have a 50% chance of a single collision. At more realistic generation rates of thousands or even millions per second, collisions are effectively impossible.
Consider some real-world scale comparisons:
The bottom line: if you are using a proper CSPRNG, UUID v4 collisions are not a practical concern. You are far more likely to experience a hardware failure, a software bug, or a meteorite impact than a UUID collision.
UUIDs are not the only option for unique identifiers. Different applications have different requirements, and understanding the tradeoffs helps you choose the right tool.
Traditional sequential integer IDs (1, 2, 3, ...) are the simplest form of identifier. They are compact, human-readable, and perfectly sorted.
| Aspect | Auto-Increment | UUID v4 |
|---|---|---|
| Size | 4-8 bytes | 16 bytes |
| Sortable | Yes | No |
| Distributed generation | Requires coordination | Independent |
| Enumerable | Yes (security risk) | No |
| Human-readable | Yes | No |
| Index performance | Excellent | Poor (fragmentation) |
When to use auto-increment: Single-database applications where IDs are internal-only, data volume is manageable, and you do not expose IDs in URLs or APIs. When to avoid: Distributed systems, microservices, or any scenario where IDs are exposed externally (auto-increment IDs leak information about your total record count and insertion rate).
ULID is a 128-bit identifier that embeds a 48-bit Unix timestamp in milliseconds followed by 80 bits of randomness. Unlike UUIDs, ULIDs are encoded using Crockford Base32, producing a 26-character string that is URL-safe and case-insensitive.
# ULID format:
01ARZ3NDEKTSV4RRFFQ69G5FAV
|----------|----------------|
Timestamp Randomness
(48 bits) (80 bits)
# ULID vs UUID comparison:
ULID: 01ARZ3NDEKTSV4RRFFQ69G5FAV (26 chars)
UUID: 550e8400-e29b-41d4-a716-446655440000 (36 chars)
Advantages over UUID: Lexicographically sortable by creation time, shorter string representation, case-insensitive, monotonically increasing within the same millisecond. Disadvantages: Less widespread tooling and database support, no standardized RFC.
nanoid is a tiny, URL-friendly, unique ID generator for JavaScript. It generates IDs using a custom alphabet and configurable length, defaulting to 21 characters using A-Za-z0-9_- (64 characters).
# nanoid examples (default 21 chars):
V1StGXR8_Z5jdHi6B-myT
kdIcMb6pXT_WxGoPNKJ2e
# Custom length:
nanoid(10) -> "IRFa-VaY2b"
nanoid(36) -> "THbfRG_ewGBksvFMjBJ7dIDh8X3o_0RMUC2c"
Advantages: Shorter IDs, URL-safe by default, configurable alphabet and length, very fast generation, tiny library size (130 bytes). Disadvantages: No timestamp component, not a standard format, collision space depends on configured length.
Originally created by Twitter, Snowflake IDs are 64-bit integers that encode a timestamp, machine ID, and sequence number. They are used by Twitter, Discord, Instagram, and other high-scale systems.
# Snowflake structure (64 bits):
# 1 bit unused | 41 bits timestamp | 10 bits machine ID | 12 bits sequence
# Can generate 4,096 IDs per millisecond per machine
Advantages: 64-bit integer (compact, fast comparisons), time-sortable, high throughput. Disadvantages: Requires machine ID coordination, limited to ~69 years of timestamps, tightly coupled to infrastructure.
UUIDs appear in virtually every layer of modern software architecture. Here are the most common and important use cases.
UUIDs are widely used as primary keys, especially in distributed databases and microservices architectures. They allow each service to generate IDs independently without coordinating with a central database or sequence generator.
-- PostgreSQL
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Insert without specifying ID
INSERT INTO users (email) VALUES ('[email protected]');
In a microservices architecture, multiple services often need to create records simultaneously. Using auto-increment IDs would require services to coordinate through a shared database or sequence service, creating a bottleneck and single point of failure. UUIDs eliminate this dependency entirely -- each service generates its own IDs locally.
Common patterns include: event sourcing (each event gets a UUID), saga orchestration (each saga instance has a UUID), and cross-service references (service A can create a UUID that service B will later use as a foreign key, without any communication between them at creation time).
Exposing auto-increment IDs in APIs is a security risk: users can enumerate resources by incrementing the ID (/api/users/1, /api/users/2, ...). UUIDs prevent this because they are unguessable:
# Bad: enumerable, leaks information
GET /api/users/42
GET /api/invoices/1337
# Good: UUIDs are unguessable
GET /api/users/7c9e6679-7425-40de-944b-e07fc1f90ae7
GET /api/invoices/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
UUIDs are commonly used as session identifiers, request correlation IDs, and trace IDs. A correlation ID assigned at the API gateway propagates through every microservice in the request chain, making it possible to trace a single user request across dozens of services and log entries:
X-Request-ID: 123e4567-e89b-12d3-a456-426614174000
X-Correlation-ID: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Cloud storage systems (S3, GCS, Azure Blob) use UUIDs or UUID-like identifiers for object keys. This prevents naming conflicts when multiple clients upload files simultaneously and distributes objects evenly across storage partitions:
# S3 object keys with UUIDs
s3://uploads/7c9e6679-7425-40de-944b-e07fc1f90ae7/profile.jpg
s3://documents/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11.pdf
Payment processors and financial APIs use UUIDs as idempotency keys. The client generates a UUID for each unique operation, and the server ensures that replaying the same request (with the same UUID) does not result in duplicate charges:
POST /v1/charges
Idempotency-Key: d7e6f8a2-3b4c-5d6e-7f8a-9b0c1d2e3f4a
{
"amount": 2000,
"currency": "usd",
"source": "tok_visa"
}
Most modern databases have native UUID support, but the implementation details, performance characteristics, and best practices vary significantly.
PostgreSQL has a native UUID data type that stores UUIDs as 128-bit binary values (16 bytes). This is more efficient than storing them as CHAR(36) strings. PostgreSQL provides built-in UUID generation functions:
-- Generate UUID v4 (built-in since PostgreSQL 13)
SELECT gen_random_uuid();
-- Result: 3b241101-e2bb-4d7b-8b11-0f6f29e45bf5
-- Using as a default primary key
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
customer_id UUID NOT NULL REFERENCES customers(id),
total DECIMAL(10, 2),
created_at TIMESTAMPTZ DEFAULT now()
);
-- The uuid-ossp extension provides additional versions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SELECT uuid_generate_v1(); -- Timestamp + MAC
SELECT uuid_generate_v4(); -- Random
SELECT uuid_generate_v5(uuid_ns_dns(), 'example.com'); -- SHA-1 hash
Performance tip: Random UUID v4 primary keys cause B-tree index page splits because new values are inserted at random positions throughout the index. For high-write tables, consider UUID v7 (which inserts sequentially) or use a separate serial column for the clustered index while exposing the UUID externally.
MySQL 8.0 added several UUID functions. While MySQL does not have a native UUID data type, you can store UUIDs as BINARY(16) for optimal performance or CHAR(36) for readability:
-- Generate UUID (v1-like in MySQL)
SELECT UUID();
-- Result: 6ccd780c-baba-1026-9564-5b8c656024db
-- Convert between string and binary for efficient storage
SELECT UUID_TO_BIN(UUID(), 1); -- Binary, swap time fields for sorting
SELECT BIN_TO_UUID(uuid_col, 1); -- Back to string
-- Efficient schema using BINARY(16)
CREATE TABLE products (
id BINARY(16) PRIMARY KEY DEFAULT (UUID_TO_BIN(UUID(), 1)),
name VARCHAR(255) NOT NULL,
price DECIMAL(10, 2)
);
-- The swap_flag (second argument = 1) in UUID_TO_BIN reorders
-- the time-based bytes to improve index locality for UUID v1
Important: MySQL's UUID() function generates version 1 UUIDs, not version 4. If you need UUID v4, generate them in your application code. The UUID_TO_BIN(uuid, 1) swap flag rearranges the timestamp bytes of v1 UUIDs to improve index performance, but this has no benefit for random v4 UUIDs.
MongoDB's default _id field uses ObjectId, a 12-byte identifier that embeds a timestamp, machine identifier, process ID, and counter. While ObjectId is not a UUID, MongoDB fully supports UUID values:
// MongoDB supports UUID as BSON type
db.users.insertOne({
_id: UUID("550e8400-e29b-41d4-a716-446655440000"),
name: "Alice",
email: "[email protected]"
});
// Generate random UUID in MongoDB shell
db.users.insertOne({
_id: UUID(), // Generates random UUID v4
name: "Bob"
});
// Query by UUID
db.users.findOne({
_id: UUID("550e8400-e29b-41d4-a716-446655440000")
});
MongoDB stores UUIDs as BSON Binary subtype 4 (16 bytes), which is more storage-efficient than string representation. If you are migrating from another database, be aware that MongoDB's UUID handling and comparison behavior differs between the Legacy UUID format (subtype 3) and the standard format (subtype 4).
| Feature | PostgreSQL | MySQL | MongoDB |
|---|---|---|---|
| Native UUID type | Yes | No (use BINARY(16)) | Yes (BSON Binary) |
| Storage size | 16 bytes | 16 bytes (BINARY) | 16 bytes |
| Built-in v4 generation | gen_random_uuid() | No (v1 only) | UUID() |
| Index performance | Good with v7 | Good with swap flag | Good (B-tree) |
Using UUIDs effectively requires understanding their tradeoffs and avoiding common mistakes. Here are the most important best practices and pitfalls to watch for.
Do not default to UUID v4 for every use case. Consider your requirements:
This is the most critical rule for UUID v4 generation. Use crypto.getRandomValues() or crypto.randomUUID() in JavaScript, uuid.uuid4() in Python, UUID.randomUUID() in Java, or Guid.NewGuid() in C#. Never use non-cryptographic random sources like Math.random().
A UUID string with hyphens is 36 characters (36 bytes in ASCII). The same UUID stored as binary is only 16 bytes -- less than half the size. For tables with millions of rows, this difference adds up significantly in storage, index size, and query performance.
-- PostgreSQL: native UUID type (16 bytes)
id UUID PRIMARY KEY
-- MySQL: BINARY(16) instead of CHAR(36)
id BINARY(16) PRIMARY KEY
-- Application code handles conversion
-- Most ORMs and database drivers handle this transparently
UUIDs are unique, but they are not secret tokens. UUID v1 leaks the MAC address and timestamp. Even UUID v4, while unguessable, should not be used as the sole authentication mechanism. If you need secret tokens, generate them using a dedicated secret generation function with sufficient entropy (at least 256 bits) and store them hashed.
UUID string comparisons are case-insensitive by the RFC, but many programming languages perform case-sensitive string comparisons by default. Always normalize UUIDs to lowercase before comparing or storing:
// These are the same UUID:
"550E8400-E29B-41D4-A716-446655440000"
"550e8400-e29b-41d4-a716-446655440000"
// Always normalize to lowercase
const normalized = uuid.toLowerCase();
While some systems store UUIDs without hyphens (550e8400e29b41d4a716446655440000), the canonical format with hyphens is the standard. Stripping hyphens saves 4 bytes but reduces readability and can cause interoperability issues. Keep the hyphens unless you have a strong reason to remove them.
Generating and working with UUIDs does not require installing libraries or writing code. Our free UUID Generator provides instant UUID generation directly in your browser with multiple features:
Generate single or bulk UUID v4 values with a single click. All UUIDs are generated using crypto.getRandomValues() directly in your browser -- no server communication, no data stored, completely private. Copy individual UUIDs or download a batch as a text file.
Paste any UUID to validate its format, identify the version and variant, and extract embedded information. For UUID v1 and v7, the tool extracts and displays the embedded timestamp. For all versions, it shows the version number, variant, and a field-by-field breakdown.
Generate UUID v4 (random) and UUID v7 (time-sortable) depending on your needs. Whether you need a random identifier for an API response or a sortable key for a database table, the right version is one click away.
Whether you are building a REST API, designing a database schema, or debugging a distributed system, our UUID Generator helps you work with UUIDs quickly and correctly.
Generate cryptographically secure UUID v4 and v7 values, validate existing UUIDs, and extract version information -- all client-side with no data sent to any server.
Try the UUID Generator NowMaster JSON formatting, validation, and manipulation with practical examples and best practices.
Learn how JWTs work, their structure, signing algorithms, and security best practices for authentication.