If you've ever built a database schema, written an API, or distributed a system across multiple servers, you've almost certainly encountered UUIDs. These 128-bit identifiers are the backbone of modern software architecture, providing a way to generate unique IDs without coordination between systems. But how exactly do they work, which version should you use, and how do you generate them in your programming language of choice?
This guide covers everything you need to know about UUIDs — from the theory behind them to practical implementation in JavaScript, Python, Java, and other popular languages.
Generate UUIDs instantly with our free online tool.
Open UUID Generator →A UUID (Universally Unique Identifier) is a 128-bit number used to uniquely identify information in computer systems. You'll also see them referred to as GUIDs (Globally Unique Identifiers) — particularly in Microsoft ecosystems. While the terms are often used interchangeably, UUID is the formal standard defined by RFC 4122.
In practice, a UUID looks like this: 550e8400-e29b-41d4-a716-446655440000. It consists of 32 hexadecimal digits displayed in five groups separated by hyphens, following the pattern 8-4-4-4-12. That's 36 characters total (32 hex digits plus 4 hyphens), which is why you'll often see UUID fields defined as CHAR(36) in databases.
The mathematical uniqueness guarantee is staggering. With 128 bits, there are approximately 3.4 × 10³⁸ possible UUIDs. To put that in perspective, if you generated one billion UUIDs per second for every second since the Big Bang, you'd still have only used a tiny fraction of the available space. Collisions are theoretically possible but practically impossible for most use cases.
Not all UUIDs are created equal. The RFC 4122 standard defines several versions, each with different generation strategies. Understanding the differences is critical for choosing the right one for your application.
Version 1 UUIDs combine the host machine's MAC address with a timestamp and a clock sequence number. This means they're time-sortable and carry embedded metadata about when and where they were generated.
Pros: Guaranteed uniqueness within a system, time-sortable (helpful for database indexing), no randomness needed.
Cons: The embedded MAC address raises privacy concerns. An attacker who sees a v1 UUID can potentially identify the generating machine and the approximate time of generation. Some implementations also have clock regression issues.
Version 3 generates a UUID by hashing a namespace and a name using MD5. Give it the same namespace and name, and it will always produce the same UUID. This makes v3 useful for deterministic identifiers — for example, generating a consistent ID for a user based on their email address.
Cons: MD5 is considered cryptographically broken. If two different inputs produce the same hash (a collision), you'd get the same UUID, which undermines the uniqueness guarantee.
Version 4 UUIDs are generated entirely from random bytes (122 random bits, plus 6 fixed bits for version and variant). This is the most common UUID version in use today, and it's what most developers think of when they hear "UUID."
Pros: No metadata leakage, simple to implement, no coordination needed.
Cons: Not time-sortable, which means inserting UUIDv4 as primary keys in a B-tree database (like PostgreSQL or MySQL) can cause index fragmentation and poor insert performance at scale.
Version 5 works like v3 but uses SHA-1 instead of MD5. The same namespace and name always produce the same UUID. SHA-1 is stronger than MD5 (though it has its own theoretical weaknesses), making v5 the recommended choice for deterministic UUIDs.
Version 7 is the newest addition, standardized in RFC 9562 (2024). It encodes a Unix timestamp in milliseconds as the first 48 bits, followed by random bits. This gives you the best of both worlds: time-sortability for database performance and randomness for uniqueness.
Pros: Time-sortable, no MAC address exposure, excellent for database primary keys, designed for modern distributed systems.
Cons: Newer standard, so library support varies. If you're working with older systems, you may need to implement or find a v7 generator.
Modern browsers and Node.js now have built-in UUID generation via the crypto module:
// Browser (modern)
const uuid = crypto.randomUUID();
console.log(uuid); // "550e8400-e29b-41d4-a716-446655440000"
// Node.js (v15.6+)
const { randomUUID } = require('crypto');
console.log(randomUUID());
For older environments or when you need specific versions, the uuid npm package is the gold standard:
npm install uuid
const { v4, v5, v7 } = require('uuid');
console.log(v4()); // Random UUID
console.log(v5('hello', v5.DNS)); // Deterministic
console.log(v7()); // Time-sortable
Python's standard library includes the uuid module with support for v1, v3, v4, and v5:
import uuid
print(uuid.uuid4()) # Random UUID
print(uuid.uuid5(uuid.NAMESPACE_DNS, 'example.com')) # Deterministic
print(uuid.uuid1()) # Time + MAC address
For UUID v7, install the uuid7 package:
pip install uuid7
import uuid7
print(uuid7.uuid7())
Java has built-in UUID support since Java 5:
import java.util.UUID;
String id = UUID.randomUUID().toString();
System.out.println(id);
For v7 support, check out libraries like uuid-creator or implement it manually using the timestamp + random pattern.
Go's standard library provides UUID generation via the google/uuid package:
import "github.com/google/uuid"
id := uuid.New()
fmt.Println(id.String())
// v7 support
id7 := uuid.Must(uuid.NewV7())
Using UUIDs as primary keys is a common pattern in distributed systems, but it comes with trade-offs that are worth understanding.
Traditional databases like PostgreSQL and MySQL use B-tree indexes. When you insert rows with sequential auto-increment IDs, new rows are appended to the end of the index — fast and efficient. Random UUIDv4 values, however, are scattered throughout the index space, causing page splits and fragmentation.
At small scale (thousands of rows), this is negligible. At large scale (millions or billions of rows), it can significantly degrade write performance and increase storage overhead.
BINARY(16) instead of CHAR(36) — this cuts storage in half and improves index performance.BINARY(16) for better performance and lower storage.UUID is the formal standard (RFC 4122). GUID is Microsoft's implementation. In practice, they're the same thing. The term "GUID" is more common in .NET and Windows environments, while "UUID" is used everywhere else. There are minor differences in formatting (GUIDs are sometimes displayed without hyphens or with braces), but the underlying structure is identical.
For UUIDv4, the probability of collision is astronomically low. The "birthday paradox" calculation suggests you'd need to generate about 2.71 quintillion (2.71 × 10¹⁸) UUIDv4 values before having a 50% chance of any collision. For UUIDv7, collisions are even less likely because the timestamp prefix distributes values across time. In practice, collisions are not something you need to worry about.
Use UUIDv7 for database primary keys, event IDs, or any scenario where sort order matters. Use UUIDv4 for one-off identifiers, testing, or when you don't care about sortability. UUIDv7 is the better default for new projects because it doesn't sacrifice anything — you get randomness AND time-sorting.
Standard UUIDs contain hyphens, which are technically allowed in URLs but can cause issues in some systems. If you need URL-safe UUIDs, simply remove the hyphens (resulting in a 32-character hex string) or use Base64 encoding (which produces a 22-character string). Both approaches preserve the full 128-bit uniqueness.
No. UUIDs are designed for uniqueness, not secrecy. UUIDv4 uses 122 bits of randomness, which is better than a 32-bit random number but far less than the 256+ bits recommended for security tokens. For passwords, API keys, session tokens, or anything security-sensitive, use a dedicated cryptographic random generator with sufficient entropy.
Use a regular expression: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i. Most languages also have built-in parsing functions — for example, UUID.fromString() in Java, uuid.UUID() in Python (which raises ValueError for invalid input), or uuid.validate() in the Node.js uuid package.
Need to generate UUIDs right now? Try our free online UUID generator.
Open UUID Generator →