TL;DR — Quick Summary
- A UUID is a 128-bit globally unique identifier standardized by RFC 4122
- UUID v4 (random) is recommended for most use cases — 122 bits of cryptographic randomness
- Python:
import uuid; uuid.uuid4() - JavaScript:
crypto.randomUUID() - No-code: use the QuickTextTools UUID Generator to generate up to 1000 at once
What Is a UUID?
A UUID (Universally Unique Identifier) is a 128-bit label used for information in computer systems. Standardized by the Open Software Foundation (OSF) as part of the Distributed Computing Environment (DCE) and formalized in RFC 4122, UUIDs are designed to be unique across space and time without requiring a central registration authority.
Unlike a sequential ID generated by a database (1, 2, 3, ...), a UUID can be independently generated by any system — a web browser, a mobile app, a microservice running in another country — and the probability that two independently generated UUIDs will be identical is effectively zero.
550e8400-e29b-41d4-a716-446655440000
time_low
time_mid
time_hi+ver
clk_seq
node
The format is standardized as five groups of hexadecimal digits separated by hyphens in the pattern 8-4-4-4-12, totaling 32 hex digits (128 bits) plus 4 hyphens — 36 characters in total.
UUID Structure Explained
Every UUID field has a defined purpose in the RFC 4122 specification. The meaning of each field varies by UUID version, but the structural positions are fixed.
| Field | Length | Description |
|---|---|---|
| time_low | 4 bytes (8 hex) | Low 32 bits of time (v1) or random bits (v4) |
| time_mid | 2 bytes (4 hex) | Middle 16 bits of time (v1) or random bits (v4) |
| time_hi_and_version | 2 bytes (4 hex) | High 12 bits of time + 4-bit version number |
| clock_seq_and_reserved | 2 bytes (4 hex) | Clock sequence + 2-bit variant identifier |
| node | 6 bytes (12 hex) | MAC address (v1) or random bits (v4) |
The Version and Variant Bits
Two fields in every UUID are reserved for metadata — not random data:
- Version digit: The first digit of the third group encodes the UUID version (1–5). In UUID v4:
xxxxxxxx-xxxx-4xxx-...— the 4 is fixed. - Variant bits: The first digit of the fourth group is restricted to 8, 9, a, or b in RFC 4122 UUIDs — encoding the variant (DCE 1.1). This is why v4 UUIDs look like
...-4xxx-[89ab]xxx-....
UUID Versions: v1, v3, v4, v5 (and v7)
RFC 4122 defines five UUID versions. Each uses a different algorithm to generate the 128-bit value. Understanding the differences helps you choose the right version for your use case.
Version 1 — Time-Based
6ba7b810-9dad-11d1-80b4-00c04fd430c8- ✓Sortable by creation time
- ✓Monotonically increasing on same machine
- ✗Reveals MAC address (privacy risk)
- ✗Requires a clock and sequence counter
- ✗Not safe for public-facing identifiers
Internal audit logs, event sourcing systems where time ordering matters and privacy is not a concern.
Version 3 — Name-Based (MD5)
6fa459ea-ee8a-3ca4-894e-db77e160355e- ✓Deterministic — same inputs always produce same UUID
- ✓No randomness required
- ✗MD5 is cryptographically broken
- ✗Not unique if names collide
- ✗Deprecated in favor of v5
Legacy systems. Avoid for new development — use v5 instead.
Version 4 — Random (Recommended)
550e8400-e29b-41d4-a716-446655440000- ✓122 bits of cryptographic randomness
- ✓No system information exposed
- ✓Simple to generate on any platform
- ✓Supported everywhere
- ✗Not time-sortable
- ✗Random insertion hurts B-tree index performance at very high volume
Database primary keys, API resource IDs, session tokens, file names — the universal default choice.
Version 5 — Name-Based (SHA-1)
886313e1-3b8a-5372-9b90-0c9aee199e5d- ✓Deterministic and reproducible
- ✓Better than v3 (SHA-1 vs MD5)
- ✓Same name+namespace always gives same UUID
- ✗SHA-1 is also deprecated for cryptographic use
- ✗Same collision risk as v3 for name conflicts
Deterministic ID generation from known inputs — URL slugs, content hashing, namespace-scoped identifiers.
Version 7 — Time-Ordered Random (Modern)
018e57cb-2b8e-7000-8000-000000000000- ✓Lexicographically sortable by creation time
- ✓Sufficient randomness for uniqueness
- ✓Better database index performance than v4
- ✓Defined in RFC 9562 (2024)
- ✗Not yet supported natively in all languages
- ✗Requires library support in most environments
Modern database primary keys where time ordering is desired. Increasingly recommended over v4 for new systems.
UUID vs GUID — What's the Difference?
The short answer: there is no technical difference. UUID and GUID refer to the same 128-bit identifier format. The naming divergence is purely historical and organizational.
UUID
Universally Unique Identifier — the term used in RFC 4122, the IETF standard. Used in Unix/Linux systems, open-source ecosystems, web APIs, and cross-platform contexts. Python's <code className="bg-violet-100 px-1 rounded">uuid</code> module, PostgreSQL's <code className="bg-violet-100 px-1 rounded">UUID</code> type, and JavaScript's <code className="bg-violet-100 px-1 rounded">crypto.randomUUID()</code> all use this terminology.
GUID
Globally Unique Identifier — Microsoft's equivalent term. Used in Windows APIs, COM interfaces, .NET's <code className="bg-blue-100 px-1 rounded">System.Guid</code>, SQL Server's <code className="bg-blue-100 px-1 rounded">UNIQUEIDENTIFIER</code> type, and Visual Studio tooling. Functionally identical to UUID — same format, same uniqueness guarantees.
One subtle difference: Microsoft's GUID generation historically used a mixed-endian byte order for the first three fields (little-endian) compared to the big-endian order in RFC 4122. This affects binary representation in SQL Server's <code className="bg-gray-100 px-1 rounded">UNIQUEIDENTIFIER</code> type but not the string representation. When comparing GUIDs and UUIDs as strings, they look and behave identically.
Generate UUIDs in Python
Python's built-in uuid module provides complete UUID generation with no external dependencies required.
Basic UUID Generation
import uuid
# UUID v4 — recommended, random
v4 = uuid.uuid4()
print(v4)
# 550e8400-e29b-41d4-a716-446655440000
print(str(v4))
# same, as string
print(v4.hex)
# 550e8400e29b41d4a716446655440000 (no dashes)
print(v4.int)
# 113059749145936325402354257176981405696 (integer)
print(v4.bytes)
# raw bytes (16 bytes)
# UUID v1 — time-based
v1 = uuid.uuid1()
print(v1)
# 6ba7b810-9dad-11d1-80b4-00c04fd430c8
# UUID v5 — name-based (SHA-1)
v5 = uuid.uuid5(
uuid.NAMESPACE_URL,
'https://quicktexttools.in'
)
print(v5)
# deterministic — same output every time for same input
# Nil UUID
nil = uuid.UUID(int=0)
print(nil)
# 00000000-0000-0000-0000-000000000000Bulk UUID Generation
import uuid
def generate_uuids(
count: int,
uppercase: bool = False,
no_dashes: bool = False
) -> list[str]:
results = []
for _ in range(count):
u = str(uuid.uuid4())
if no_dashes:
u = u.replace('-', '')
if uppercase:
u = u.upper()
results.append(u)
return results
# Generate 1000 UUIDs and save to file
uuids = generate_uuids(1000)
with open('uuids.txt', 'w') as f:
f.write('\n'.join(uuids))
print(f"Saved {len(uuids)} UUIDs to uuids.txt")UUID Validation in Python
import uuid
def is_valid_uuid(value: str) -> bool:
try:
uuid.UUID(str(value))
return True
except ValueError:
return False
print(
is_valid_uuid(
"550e8400-e29b-41d4-a716-446655440000"
)
)
# True
print(
is_valid_uuid("not-a-uuid")
)
# False
print(
is_valid_uuid(
"550e8400e29b41d4a716446655440000"
)
)
# True (no dashes OK)
# Validate and get version
def get_uuid_version(value: str) -> int | None:
try:
return uuid.UUID(str(value)).version
except ValueError:
return NoneGenerate UUIDs in JavaScript
Modern JavaScript environments expose the Web Crypto API's <code className="bg-gray-100 px-1 rounded">crypto.randomUUID()</code> method — the fastest and most reliable way to generate UUID v4 with no dependencies.
Browser & Node.js 19+ (Native)
// Native — works in modern browsers and Node.js 19+
const uuid = crypto.randomUUID();
console.log(uuid);
// '550e8400-e29b-41d4-a716-446655440000'
// Bulk generation
function generateUuids(
count,
{ uppercase = false, noDashes = false } = {}
) {
return Array.from(
{ length: count },
() => {
let u = crypto.randomUUID();
if (noDashes) {
u = u.replace(/-/g, '');
}
if (uppercase) {
u = u.toUpperCase();
}
return u;
}
);
}
const uuids = generateUuids(
100,
{ uppercase: true }
);
console.log(uuids.length);
// 100With the uuid npm Package (Universal)
// npm install uuid
import {
v4 as uuidv4,
v1 as uuidv1,
v5 as uuidv5,
NIL,
validate,
version,
} from 'uuid';
// v4 — random
console.log(uuidv4());
// 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
// v1 — time-based
console.log(uuidv1());
// time-ordered UUID
// v5 — name-based
const NAMESPACE =
'6ba7b810-9dad-11d1-80b4-00c04fd430c8';
console.log(
uuidv5('hello', NAMESPACE)
);
// deterministic
// nil UUID
console.log(NIL);
// '00000000-0000-0000-0000-000000000000'
// Validation
console.log(
validate(
'550e8400-e29b-41d4-a716-446655440000'
)
);
// true
console.log(
version(
'550e8400-e29b-41d4-a716-446655440000'
)
);
// 4Polyfill for Older Browsers
function generateUUIDv4() { if (typeof crypto !== 'undefined' && crypto.randomUUID) { return crypto.randomUUID(); } // Fallback using Math.random (less secure — use only if crypto unavailable) return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }Generate UUIDs in Java & Other Languages
import java.util.UUID;
// UUID v4 — random
UUID uuid = UUID.randomUUID();
System.out.println(uuid.toString());
// "550e8400-e29b-41d4-a716-446655440000"
// Without dashes
String compact =
uuid.toString().replace("-", "");
System.out.println(compact);
// UUID v3 (name-based)
UUID v3 =
UUID.nameUUIDFromBytes(
"hello".getBytes()
);
// Validate a UUID string
UUID parsed =
UUID.fromString(
"550e8400-e29b-41d4-a716-446655440000"
);using System;
// UUID (GUID) v4
Guid guid = Guid.NewGuid();
Console.WriteLine(guid.ToString());
// lowercase with dashes
Console.WriteLine(guid.ToString("N"));
// compact, no dashes
Console.WriteLine(guid.ToString("B"));
// {with-braces}
Console.WriteLine(guid.ToString("X"));
// {0x...,0x...} hex format
// Nil GUID
Guid nil = Guid.Empty;
Console.WriteLine(nil);
// 00000000-0000-0000-0000-000000000000
// Parse and validate
bool isValid = Guid.TryParse(
"550e8400-e29b-41d4-a716-446655440000",
out Guid result
);// go get github.com/google/uuid
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
// UUID v4
id := uuid.New()
fmt.Println(id.String())
// UUID v1
id1, _ := uuid.NewUUID()
fmt.Println(id1.String())
// Nil UUID
fmt.Println(uuid.Nil.String())
// Validate
parsed, err := uuid.Parse(
"550e8400-e29b-41d4-a716-446655440000"
)
fmt.Println(parsed, err)
}UUIDs in Databases
Database support for UUIDs varies significantly. Choosing the right storage strategy has meaningful performance implications at scale.
PostgreSQL
Native UUID type (16 bytes)
gen_random_uuid() (pgcrypto) or uuid_generate_v4() (uuid-ossp)
PostgreSQL has the best native UUID support. Use UUID as the column type directly. The gen_random_uuid() function is available without extensions in PostgreSQL 13+.
CREATE TABLE users (id UUID PRIMARY KEY DEFAULT gen_random_uuid());MySQL / MariaDB
BINARY(16) recommended; CHAR(36) as fallback
UUID() built-in function (v1); application-side for v4
MySQL 8.0+ includes UUID_TO_BIN() and BIN_TO_UUID() helpers. For MySQL 8.0.13+, UUID_TO_BIN(uuid, true) swaps bytes for better index performance.
CREATE TABLE users (id BINARY(16) PRIMARY KEY DEFAULT (UUID_TO_BIN(UUID(), 1)));SQL Server
UNIQUEIDENTIFIER (native 16-byte type)
NEWID() (random) or NEWSEQUENTIALID() (sequential, index-friendly)
NEWSEQUENTIALID() generates sequential GUIDs optimized for clustered index performance. Use NEWID() for security-sensitive public identifiers.
CREATE TABLE users (id UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWSEQUENTIALID());SQLite
TEXT (no native UUID type)
Application-side generation required
SQLite has no UUID type or generation function. Store as TEXT(36) with dashes or BLOB(16) for compactness. Generate UUID v4 in your application layer.
CREATE TABLE users (id TEXT PRIMARY KEY); -- insert UUIDs from applicationUUID vs Auto-Increment Primary Keys
This is one of the most frequently debated decisions in backend architecture. There is no universal right answer — the correct choice depends on your system's requirements.
| Criterion | UUID v4 | Auto-Increment |
|---|---|---|
| Global uniqueness | ✅ Guaranteed across systems | ❌ Only unique within one database |
| Index performance | ⚠️ Random insertion causes page splits | ✅ Sequential — optimal B-tree performance |
| Storage size | ⚠️ 16 bytes (BINARY) or 36 bytes (TEXT) | ✅ 4–8 bytes (INT/BIGINT) |
| Predictability/security | ✅ Non-guessable, non-sequential | ❌ Sequential — enables enumeration attacks |
| Client-side generation | ✅ Generate anywhere without DB | ❌ Requires database round-trip |
| Distributed systems | ✅ No coordination needed | ❌ Requires centralized counter or sharding |
| Human readability | ❌ 36-character opaque string | ✅ Short, readable integers |
| Merge/replication | ✅ No ID conflicts across nodes | ❌ ID conflicts require remapping |
The Hybrid Approach — Best of Both Worlds
Many modern systems use both: an auto-increment integer as the internal primary key (for join performance and index efficiency) alongside a UUID column as the public identifier (for API resources and external references). The integer key is never exposed; all external APIs use the UUID. This gives optimal database performance while maintaining the security and distribution benefits of UUIDs.
UUID Security Considerations
UUID v4 is safe for public-facing identifiers
With 122 bits of cryptographic randomness from the OS CSPRNG, UUID v4 is unpredictable and resistant to brute-force guessing. An attacker cannot enumerate resources by incrementing an ID or predict the next UUID from previous ones.
UUID v1 leaks system information
UUID v1 embeds the MAC address of the generating machine in the node field. This can be used to identify the specific hardware that generated the UUID — a potential privacy and security issue for public-facing identifiers. Always use v4 for public IDs.
UUIDs are not secrets — they are identifiers
A UUID used as a resource ID is not a secret. If a user can access a resource at /api/documents/550e8400-..., they know the UUID. A UUID's security comes from its unpredictability, not from being hidden. For true secrets (passwords, API keys), use a cryptographically random token of at least 256 bits, not a UUID.
Always enforce authorization, not just obscurity
Do not rely on UUID unpredictability as your only authorization mechanism. Always check that the requesting user has permission to access the resource with that UUID. UUID unpredictability is a defense-in-depth measure, not a substitute for proper access control.
Best Practices for Working with UUIDs
Use UUID v4 as your default choice
Unless you have a specific reason to use v1 (time-sorting) or v5 (deterministic), UUID v4 is the correct default for all new applications.
Store as BINARY(16), not VARCHAR(36)
Binary storage is 2.25× more compact than string storage and index lookups are significantly faster. Only convert to string representation at the application boundary.
Always enforce a UNIQUE database constraint
Even though UUID collisions are effectively impossible, a UNIQUE constraint is correct schema design. It documents your intent and provides a safety net.
Normalize case before storage
Choose lowercase (RFC 4122 standard) and enforce it consistently. Mixed-case UUIDs that differ only by case create subtle bugs in case-sensitive comparisons.
Consider UUID v7 for new high-throughput systems
UUID v7's time-ordered prefix maintains B-tree index locality while providing sufficient randomness. For new greenfield projects with high insert rates, v7 is worth evaluating.
Use crypto.randomUUID() in the browser, not Math.random()
Math.random() is not cryptographically secure. Always use the Web Crypto API's crypto.randomUUID() for any UUID used in a security-sensitive context.
Common Mistakes to Avoid
✗Using Math.random() to generate UUIDs in JavaScript
Math.random() is not cryptographically secure. Its output is predictable with sufficient observation. Always use crypto.randomUUID() or the uuid npm package which uses the CSPRNG under the hood.
✗Treating UUIDs as case-sensitive strings without normalization
An API that stores UUIDs as generated (mixed or uppercase) will fail to find records when the client sends the UUID in a different case. Always normalize to lowercase before storage and lookup.
✗Using UUID v1 for public-facing resource identifiers
UUID v1 embeds your server's MAC address and can be used to reconstruct the approximate time a resource was created. Use UUID v4 for any identifier exposed outside your system.
✗Skipping the UNIQUE constraint because 'UUIDs can't collide'
Relying on collision impossibility as your uniqueness guarantee is an engineering antipattern. The UNIQUE constraint is correct schema design regardless of collision probability.
✗Storing UUIDs as VARCHAR(36) in performance-critical tables
String-based UUID storage bloats indexes and slows lookups compared to BINARY(16). For tables with millions of rows, this becomes a significant performance bottleneck.
Generate UUIDs Instantly — No Code Required
Bulk generate up to 1000 UUID v4, v1, or nil identifiers with formatting options. Copy or download instantly.
Open UUID Generator ToolFrequently Asked Questions
Conclusion
UUIDs are a foundational tool in modern software engineering — essential for distributed systems, secure API design, and scalable database architecture. Understanding the differences between versions, the storage trade-offs across database engines, and the security implications of each version allows you to make informed decisions rather than cargo-culting a solution from a Stack Overflow snippet.
For the vast majority of use cases, UUID v4 generated using your platform's cryptographically secure random number generator is the right choice. For high-throughput database workloads where index performance is critical, evaluate UUID v7 or a hybrid approach. For deterministic identifier generation from known inputs, v5 is the correct tool.
Store UUIDs as BINARY(16) in performance-critical tables, always enforce a UNIQUE constraint, normalize to lowercase, and use the UUID as a public identifier alongside an auto-increment surrogate key when maximum index performance is required.