UUID vs GUID: Complete Guide to Universally Unique Identifiers
If you have ever built a database, worked with REST APIs, or collaborated on distributed systems, you have almost certainly encountered UUIDs or GUIDs. These cryptic strings of hexadecimal characters — like 550e8400-e29b-41d4-a716-446655440000 — are one of the most widely used identifier formats in modern software. Yet the terminology around them creates real confusion. This guide covers everything you need to know: what they are, how the versions differ, when to use each, and how to generate them in the languages you already write.
What Is a UUID?
A UUID (Universally Unique Identifier) is a 128-bit label used to uniquely identify information in computer systems. The standard is defined in RFC 4122 and its successor RFC 9562. The key guarantee: a UUID generated on one machine, at any point in time, should be unique enough to be used alongside UUIDs generated on any other machine without coordination between the two.
A UUID is always represented as 32 lowercase hexadecimal digits displayed in five hyphen-separated groups, following the pattern 8-4-4-4-12. The canonical form looks like this:
The total length is always 36 characters (32 hex digits plus 4 hyphens). Because they can be generated without a central authority — no registry, no database sequence, no coordination — UUIDs are especially valuable in distributed systems, microservices, and offline-first applications.
<\!-- ==================================================== Section 2: UUID vs GUID ===================================================== -->UUID vs GUID: Are They the Same?
Short answer: yes, for all practical purposes they are identical.
GUID (Globally Unique Identifier) is simply Microsoft's term for UUID. Microsoft introduced GUIDs in COM (Component Object Model) and has used the term throughout Windows APIs, .NET, and SQL Server ever since. Both are 128-bit values; both follow the same hyphenated hex format; both are based on the same RFC standards.
The only meaningful historical difference involves byte ordering. Very early Microsoft GUID implementations serialized certain fields in little-endian order rather than big-endian, which matters when you are comparing raw bytes across platforms (for example, storing a UUID in a SQL Server uniqueidentifier column and then reading it in a PostgreSQL uuid column). Modern systems abstract this away, and you will almost never encounter a real mismatch unless you are doing low-level binary serialization across Microsoft and non-Microsoft boundaries.
In practice: when a Windows or .NET developer says GUID, they mean the same thing a Linux or database developer means by UUID. The terms are interchangeable in conversation.
<\!-- ==================================================== Section 3: Anatomy ===================================================== -->Anatomy of a UUID
A UUID is not just random bytes — each segment carries meaning. Understanding the layout helps when debugging and choosing the right version.
- Time low (bits 0–31): In time-based UUIDs (v1, v6, v7), this holds the lowest 32 bits of a timestamp. In v4, this field is random.
- Time mid (bits 32–47): The middle 16 bits of the timestamp (or random in v4).
- Time high and version (bits 48–63): The top 12 bits of the timestamp plus the 4-bit version number. The version field is what tells you whether you have a v1, v4, v5, etc. UUID.
- Clock sequence and variant (bits 64–79): Two bits encode the variant (always
10in RFC 4122 UUIDs), with the remainder used for clock sequencing in time-based versions or randomness in v4. - Node (bits 80–127): In v1, this is the MAC address of the generating machine. In v4 this is random. In v7 this carries additional timestamp precision and random bits.
The version digit is always the first character of the third group. In 550e8400-e29b-41d4-a716-446655440000, the bold 4 tells you this is a UUID v4. Similarly, a v1 UUID starts that group with 1, a v5 with 5, and so on.
UUID Versions Explained
The RFC defines multiple UUID generation algorithms, each suited to different use cases. Here is a breakdown of each version and when you would choose it.
Version 1 — Time-Based with MAC Address
UUID v1 combines the current timestamp (in 100-nanosecond intervals since October 1582) with the MAC address of the network interface that generated it. Because the timestamp is embedded, v1 UUIDs are sortable by generation time when sorted lexicographically — at least within a single machine. The downside is significant: the embedded MAC address exposes the physical hardware identity of the generating server, which is a privacy and security concern. In production systems handling sensitive data, v1 is rarely a good choice.
Version 2 — DCE Security
UUID v2 is a variant of v1 that replaces part of the timestamp with a POSIX UID/GID or domain identifier for Distributed Computing Environment (DCE) security purposes. In practice, v2 is almost never used outside of legacy DCE infrastructure. You are unlikely to encounter it in modern software.
Version 3 — MD5 Namespace-Based
UUID v3 is generated by hashing a namespace UUID and a name together using MD5. The result is deterministic: the same namespace + name combination always produces the same UUID. This makes v3 useful when you need stable identifiers for known inputs — for example, generating a consistent ID for a URL or a username across systems. The trade-off is MD5's collision vulnerability, which is why v5 (SHA-1) is generally preferred over v3 today.
Version 4 — Random
UUID v4 uses 122 bits of cryptographically random data (with 6 bits reserved for variant and version). There is no timestamp, no MAC address, no namespace — just randomness. This is by far the most widely used UUID version. It is simple to generate, requires no coordination, reveals no information about the generating system, and its collision probability is negligible for all real-world workloads.
Version 5 — SHA-1 Namespace-Based
UUID v5 works exactly like v3 but uses SHA-1 instead of MD5, making it the preferred choice for namespace-based deterministic UUIDs. When you need to produce the same UUID from the same input every time — and you need it to be secure — v5 is the right tool.
| Version | Algorithm | When to Use | Predictable? |
|---|---|---|---|
| v1 | Timestamp + MAC address | Time-ordered IDs on trusted internal networks | Yes |
| v2 | Timestamp + DCE domain | Legacy DCE systems only | Yes |
| v3 | MD5(namespace + name) | Stable IDs from known inputs (legacy) | Yes |
| v4 | Random (122 bits) | General purpose — the safe default | No |
| v5 | SHA-1(namespace + name) | Stable IDs from known inputs (preferred over v3) | Yes |
| v7 | Unix timestamp + random | Sortable IDs for databases and event logs | No |
Why UUID v4 Is the Most Popular
UUID v4 has become the de facto standard for a straightforward reason: it is the simplest option that also leaks zero information about the generating system.
Advantages of UUID v4:
- No dependency on system time, network interface, or any external state.
- Requires no coordination between nodes — multiple servers can generate UUIDs simultaneously with no risk of conflict.
- Does not expose server MAC addresses or timestamps, which is important for security-sensitive APIs and public-facing IDs.
- Native support in virtually every programming language and database engine.
- Dead simple to implement: just read 16 bytes from a cryptographic random source and set the version and variant bits.
The main limitation:
- UUID v4 values are not sortable by creation time. Inserted into a B-tree index in random order, they cause index fragmentation and page splits — a measurable performance penalty at scale. This is why UUID v7 was introduced.
UUID v7: The New Standard
UUID v7 was standardized in RFC 9562 (published May 2024) and solves the biggest practical problem with v4: database performance. A v7 UUID embeds a Unix millisecond timestamp in its most significant bits, meaning UUIDs generated in sequence sort in the order they were created.
This matters enormously for relational databases. B-tree indexes are most efficient when rows are inserted in key order. Sequential integer IDs (1, 2, 3, …) are optimal. Random UUID v4 IDs are worst-case. UUID v7 gives you the best of both worlds: globally unique, no coordination required, and monotonically increasing within the same millisecond via random sub-millisecond bits.
A UUID v7 looks like any other UUID from the outside, but the first 12 hex characters encode the millisecond timestamp:
-- UUID v7 — first 12 chars are the timestamp in milliseconds
018f24e7-a3b1-7c2d-9a0e-4f1c2b3d5e6f
^^^^^^^^^^ ↑ version = 7
UUID v7 is the recommended choice for new database schemas where you want globally unique primary keys with good index performance. As of 2025, native support is available in PostgreSQL (via extensions), and most UUID libraries have added v7 generation.
<\!-- CTA Box 1 -->Generate Hashes and Checksums Instantly
Need MD5, SHA-1, SHA-256, or other hashes for your data? SnapUtils Hash Generator runs entirely in your browser — nothing leaves your machine.
Open Hash Generator →Generating UUIDs in Code
Every major language and database provides a way to generate UUIDs. Here are the canonical patterns.
JavaScript — Browser & Node.js
Modern environments expose crypto.randomUUID() natively, which generates a v4 UUID. This is the preferred approach — no dependencies, available in all modern browsers and Node.js 14.17+.
// Native — available in all modern browsers and Node.js 14.17+
const id = crypto.randomUUID();
console.log(id); // "110e8400-e29b-41d4-a716-446655440000"
// npm 'uuid' package — supports all versions
import { v4 as uuidv4, v7 as uuidv7 } from 'uuid';
const randomId = uuidv4(); // UUID v4
const sortableId = uuidv7(); // UUID v7 — time-ordered
// UUID v5 — deterministic from namespace + name
import { v5 as uuidv5 } from 'uuid';
const MY_NAMESPACE = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
const stableId = uuidv5('user@example.com', MY_NAMESPACE);
Python
Python's standard library includes the uuid module with support for v1, v3, v4, and v5.
import uuid
# UUID v4 — random
random_id = uuid.uuid4()
print(random_id) # UUID('550e8400-e29b-41d4-a716-446655440000')
print(str(random_id)) # '550e8400-e29b-41d4-a716-446655440000'
# UUID v1 — time-based with MAC address
time_id = uuid.uuid1()
# UUID v5 — deterministic
stable_id = uuid.uuid5(uuid.NAMESPACE_URL, 'https://snaputils.tools')
SQL — PostgreSQL
PostgreSQL has first-class UUID support. Use the native gen_random_uuid() function (available since PostgreSQL 13 without any extension) for v4 UUIDs.
-- Generate a UUID v4 (built-in since PG 13)
SELECT gen_random_uuid();
-- Use as a default primary key
CREATE TABLE users (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
name TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
-- pgcrypto extension (for older PG versions)
CREATE EXTENSION IF NOT EXISTS pgcrypto;
SELECT gen_random_uuid(); -- same function
CLI — Shell
On macOS and most Linux distributions, the uuidgen command generates a UUID directly from the terminal.
# Generate a UUID (v4 on macOS, v1 on some Linux distros)
$ uuidgen
3F2504E0-4F89-41D3-9A0C-0305E82C3301
# Lowercase output
$ uuidgen | tr '[:upper:]' '[:lower:]'
3f2504e0-4f89-41d3-9a0c-0305e82c3301
# Generate 5 UUIDs at once
$ for i in {1..5}; do uuidgen; done
<\!-- ====================================================
Section 8: Collision Probability
===================================================== -->
Collision Probability: How Safe Are UUIDs?
UUID v4 has 122 bits of randomness (the other 6 bits are fixed for version and variant). The total number of possible v4 UUIDs is 2122, or approximately 5.3 × 1036 — that is 5.3 undecillion unique values.
To put that in perspective using the birthday problem: to reach a 50% probability of any collision, you would need to generate approximately 2.71 × 1018 UUIDs — that is 2.7 quintillion. If you generated 1 billion UUIDs per second, it would take approximately 85 years to reach that threshold.
The only caveat is a poor random number generator. UUID v4's safety relies entirely on the quality of the entropy source. Always use a cryptographically secure RNG — crypto.randomUUID() in browsers/Node, the secrets module in Python, gen_random_uuid() in PostgreSQL. Never use Math.random() to build a UUID.
UUID as Primary Keys
Using UUIDs as database primary keys is a common and often correct choice, but it comes with specific trade-offs worth understanding.
Advantages
- No ID enumeration attacks. Sequential integer IDs (
/users/1,/users/2) reveal record counts and enable automated scraping. UUIDs are opaque. - Safe merging. When merging data from multiple databases or shards, UUID IDs never collide. Integer IDs frequently do.
- Client-side generation. The application (or even the browser) can generate the ID before the database row is written. This simplifies optimistic UI updates and offline-first patterns.
- Decoupled systems. Microservices can generate IDs independently without a central sequence generator.
Disadvantages
- Storage size. A UUID stored as text is 36 bytes; as a native
uuidtype it is 16 bytes. A 4-byte integer is still 4x smaller, which matters when a UUID is repeated in dozens of foreign key columns. - Index fragmentation (v4). Random UUID v4 keys insert into unpredictable positions in a B-tree index, causing frequent page splits and poor cache locality. At hundreds of millions of rows, this creates a measurable performance difference versus sequential keys.
- Human readability. Integers are easy to type, copy, and discuss (
user 42). UUIDs are not.
The index fragmentation problem is the most significant concern and is why UUID v7 is now the recommended choice for primary keys when you want the benefits of UUIDs without the performance penalty. Its embedded timestamp ensures lexicographic ordering matches insertion order.
<\!-- ==================================================== Section 10: UUID vs Sequential IDs ===================================================== -->When to Use UUIDs vs Sequential IDs
The choice between UUIDs and sequential integers comes down to your system's requirements. Here is a practical decision guide:
| Scenario | Recommended Approach |
|---|---|
| Single-database application with no external ID exposure | Sequential integer (SERIAL / BIGSERIAL) |
| ID appears in public URLs or API responses | UUID v4 or v7 |
| Distributed system / multi-region writes | UUID v7 (sortable, no coordination) |
| Merging data from multiple sources | UUID v4 or v7 |
| Client generates ID before server write | UUID v4 or v7 |
| Deterministic ID from a known input | UUID v5 |
| High-write database with large indexes | UUID v7 or ULID |
| Human-readable internal tooling | Sequential integer |
A common pattern in production systems is to use both: a sequential integer as the internal primary key (for join performance) and a UUID as the external, public-facing identifier. The integer stays inside the database; the UUID travels through APIs, URLs, and logs.
<\!-- ==================================================== Section 11: URL-Safe UUIDs ===================================================== -->URL-Safe UUIDs
Standard UUID format includes hyphens (-) and uses only hex characters, making it URL-safe by default. However, 36 characters in a URL can feel verbose. Two common strategies reduce UUID size:
Removing Hyphens
Strip the hyphens to get a 32-character compact UUID. This is still unambiguous and parseable, and many frameworks accept it:
JavaScriptconst uuid = '550e8400-e29b-41d4-a716-446655440000';
const compact = uuid.replaceAll('-', '');
// '550e8400e29b41d4a716446655440000'
// Restore from compact
const restored = compact.replace(
/^(.{8})(.{4})(.{4})(.{4})(.{12})$/,
'$1-$2-$3-$4-$5'
);
Base64url Encoding
Encoding the 16 raw bytes as Base64url produces a 22-character string with no padding — significantly shorter than the 36-character hyphenated form, and safe in URLs without percent-encoding:
JavaScript (Node.js)import { parse, stringify } from 'uuid';
// UUID to Base64url (22 chars)
function uuidToBase64url(uuid) {
const bytes = parse(uuid); // Uint8Array of 16 bytes
return Buffer.from(bytes)
.toString('base64url'); // e.g. "VQ6EAOKbQdSnFkRmVUQAAA"
}
// Base64url back to UUID
function base64urlToUuid(b64) {
const bytes = Buffer.from(b64, 'base64url');
return stringify(new Uint8Array(bytes));
}
Base64url-encoded UUIDs are commonly used in short URLs, JWT token identifiers, and any context where compactness matters but full randomness is required.
<\!-- CTA Box 2 -->Hash Your Data Securely
UUID v3 and v5 use MD5 and SHA-1 respectively to generate deterministic identifiers. Use the SnapUtils Hash Generator to compute and verify hashes for any input — SHA-256, SHA-512, MD5, and more.
Try Hash Generator →Frequently Asked Questions
Is UUID the same as GUID?
Yes, UUID and GUID refer to the same concept. GUID (Globally Unique Identifier) is Microsoft's term for what the broader industry calls a UUID (Universally Unique Identifier). Both follow the same 128-bit format defined in RFC 4122, though older Microsoft implementations had minor byte-order differences in raw binary serialization. In modern applications the terms are completely interchangeable.
Which UUID version should I use?
For most applications, UUID v4 (random) is the safest and simplest choice — just call crypto.randomUUID() and you are done. If you need sortable, time-ordered identifiers for database primary keys, UUID v7 is the modern recommendation. Use v3 or v5 when you need deterministic IDs derived from a namespace and a name — for example, generating a stable UUID for a given URL.
Can two UUIDs ever be the same?
In theory yes, but the probability is astronomically small. For UUID v4, you would need to generate approximately 2.7 quintillion UUIDs to reach a 50% chance of any single collision. Generating a billion UUIDs per second continuously for 85 years would still only give you a coin-flip chance of a collision. In practice, UUIDs are treated as collision-free for all real-world use cases.
Are UUIDs good for database primary keys?
UUIDs offer meaningful security and distribution advantages over sequential integers, but random UUIDs (v4) can degrade database index performance at scale due to random insertion order causing B-tree page splits. UUID v7, which embeds a millisecond timestamp, is largely monotonically increasing and solves this problem. For new schemas where you want globally unique keys with good index performance, UUID v7 is the recommended choice.
How do I generate a UUID in JavaScript?
In modern environments, use the built-in crypto.randomUUID() method, which returns a UUID v4 string and is available in all modern browsers and Node.js 14.17+. For additional version support (v5, v7, etc.), use the uuid npm package: import { v4 as uuidv4 } from 'uuid'; const id = uuidv4();
<\!-- Related Articles -->