Generating unique identifiers is a fundamental requirement in software development, from database primary keys and session tokens to distributed system coordination and file naming. Python's built-in uuid module provides a reliable, standardized way to create Universally Unique Identifiers (UUIDs) as defined by RFC 4122, ensuring that each ID is virtually guaranteed to be unique across time and space.
In this guide, you'll learn how to generate random IDs using different UUID versions, understand their internal structure, and choose the right approach based on your uniqueness, privacy, and security requirements.
What Is a UUID?
A UUID (Universally Unique Identifier) is a 128-bit value formatted as a 32-character hexadecimal string with hyphens:
fbd204a7-318e-4dd3-86e0-e6d524fc3f98The probability of generating two identical UUIDs is astronomically low: roughly 1 in 5.3 × 10³⁶. This makes them safe to use as unique identifiers without any central coordination.
Python's uuid module supports several UUID versions:
| Version | Based On | Privacy Safe | Use Case |
|---|---|---|---|
uuid1() |
Timestamp + MAC address | ❌ | Time-ordered IDs, logging |
uuid3() |
MD5 hash of namespace + name | ✅ | Deterministic IDs from names |
uuid4() |
Random numbers | ✅ | General-purpose unique IDs |
uuid5() |
SHA-1 hash of namespace + name | ✅ | Deterministic IDs (more secure than uuid3) |
Method 1: Using uuid4() (Recommended for Most Cases)
uuid4() generates a UUID using 122 bits of randomness, with no dependence on hardware or timestamps. This is the most commonly used version and the best default choice:
import uuid
uid = uuid.uuid4()
print("Random UUID:", uid)
print("As string: ", str(uid))Output:
Random UUID: 613a4e90-8659-4c22-a22a-2ce344316154
As string: 613a4e90-8659-4c22-a22a-2ce344316154Why uuid4() Is Usually the Best Choice
- No privacy leaks: Doesn't expose your MAC address or system time.
- No coordination needed: Can be generated independently on any machine.
- Extremely low collision probability: Safe for databases, APIs, and distributed systems.
- Simple: Just call
uuid.uuid4(): no configuration required.
Common Formats
import uuid
uid = uuid.uuid4()
print("Standard: ", uid) # With hyphens
print("Hex: ", uid.hex) # 32 chars, no hyphens
print("Integer: ", uid.int) # 128-bit integer
print("Bytes: ", uid.bytes) # 16-byte string
print("URN: ", uid.urn) # URN formatOutput:
Standard: 622cea47-3525-4dd7-a623-4550b9391fd5
Hex: 622cea4735254dd7a6234550b9391fd5
Integer: 130497556374191884339973281723981570005
Bytes: b'b,\xeaG5%M\xd7\xa6#EP\xb99\x1f\xd5'
URN: urn:uuid:622cea47-3525-4dd7-a623-4550b9391fd5Generating Multiple UUIDs
import uuid
for i in range(5):
print(f"ID {i + 1}: {uuid.uuid4()}")Output:
ID 1: 4566732f-8f20-4092-963c-cfc9e6d31067
ID 2: 4363d75e-51e7-484c-a1de-cb1ba8647ea8
ID 3: efa93ee9-f0a9-4b54-aeb1-1df5a12fa6ee
ID 4: 5739980c-b2a1-44d1-b7d4-edb413a877cb
ID 5: cf516b69-de55-4515-ba55-973af60bc387Method 2: Using uuid1() (Time-Based)
uuid1() generates a UUID using the current timestamp and the machine's MAC address. This guarantees uniqueness and provides time-ordering, but exposes hardware information:
import uuid
uid = uuid.uuid1()
print("UUID1:", uid)Output:
UUID1: ecc72432-09f3-11f1-ac2f-7aedd2986efeExploring UUID1 Components
import uuid
uid = uuid.uuid1()
print("Byte repr:", repr(uid.bytes))
print("Integer: ", uid.int)
print("Hex: ", uid.hex)
print("\nVersion:", uid.version)
print("Variant:", uid.variant)
print("\nFields:", uid.fields)
print("Time Low: ", uid.fields[0])
print("Time Mid: ", uid.fields[1])
print("Time Hi: ", uid.fields[2])
print("Clock Seq Hi: ", uid.fields[3])
print("Clock Seq Low:", uid.fields[4])
print("Node (MAC): ", uid.fields[5])Output:
Byte repr: b'\xf2I$\x14\t\xf3\x11\xf1\x92 z\xed\xd2\x98n\xfe'
Integer: 322052944405010884204009590938400222974
Hex: f249241409f311f192207aedd2986efe
Version: 1
Variant: specified in RFC 4122
Fields: (4064879636, 2547, 4593, 146, 32, 135161859043070)
Time Low: 4064879636
Time Mid: 2547
Time Hi: 4593
Clock Seq Hi: 146
Clock Seq Low: 32
Node (MAC): 135161859043070Method 3: Using uuid3() and uuid5() (Name-Based, Deterministic)
These versions generate deterministic UUIDs from a namespace and a name. The same inputs always produce the same UUID:
import uuid
uid3 = uuid.uuid3(uuid.NAMESPACE_DNS, 'example.com')
print("UUID3:", uid3)
uid5 = uuid.uuid5(uuid.NAMESPACE_DNS, 'example.com')
print("UUID5:", uid5)
uid5_again = uuid.uuid5(uuid.NAMESPACE_DNS, 'example.com')
print("Same? ", uid5 == uid5_again)Output:
UUID3: 9073926b-929f-31c2-abc9-fad77ae3e8eb
UUID5: cfbff0d1-9375-5685-968c-48ce8b15ae17
Same? TrueAvailable namespaces include NAMESPACE_DNS, NAMESPACE_URL, NAMESPACE_OID, and NAMESPACE_X500.
Practical Examples
Using UUIDs as Database Keys
import uuid
class User:
def __init__(self, name, email):
self.id = str(uuid.uuid4())
self.name = name
self.email = email
user = User("Alice", "alice@example.com")
print(f"User ID: {user.id}")
print(f"Name: {user.name}")Output:
User ID: 85824d32-8776-4b8b-9558-72f55eef1d3c
Name: AliceGenerating Short IDs from UUIDs
Full UUIDs are 36 characters long. If you need shorter IDs, you can truncate or encode them:
import uuid
uid = uuid.uuid4()
short_id = uid.hex[:8]
print(f"Full UUID: {uid}")
print(f"Short ID: {short_id}")Output:
Full UUID: d525e374-7b31-43ab-b13a-b30dbea591c0
Short ID: d525e374Generating Unique Filenames
import uuid
def generate_filename(extension='txt'):
return f"{uuid.uuid4().hex[:12]}.{extension}"
print(generate_filename('txt'))
print(generate_filename('png'))
print(generate_filename('csv'))Output:
bd1d2f0248b4.txt
6d5239bea811.png
4d133acdc7e8.csvCommon Mistake: Using UUIDs for Security Tokens
UUIDs are designed for uniqueness, not security. uuid4() uses Python's random module, which may not be cryptographically secure in all implementations:
import uuid
token = str(uuid.uuid4())Use the secrets module instead for security-sensitive identifiers:
import secrets
token = secrets.token_hex(16)
print("Secure token:", token)
url_token = secrets.token_urlsafe(16)
print("URL-safe token:", url_token)Output:
Secure token: 9f8958cd1a5458e87e3d11ee6350f74d
URL-safe token: RXr18jE1GW7yyHZ_yiio4gChoosing the Right UUID Version
| Requirement | Recommended Version |
|---|---|
| General-purpose unique ID | uuid4() |
| Time-ordered ID (non-sensitive) | uuid1() |
| Deterministic ID from a name | uuid5() (or uuid3()) |
| Security token / API key | Use secrets module instead |
| Short unique ID | uuid4().hex[:N] (with collision risk) |
Summary
Python's uuid module provides a simple, reliable way to generate unique identifiers:
- Use
uuid4()as your default: it's random, privacy-safe, and requires no configuration. - Use
uuid1()when you need time-ordering, but be aware it exposes your MAC address. - Use
uuid5()when you need deterministic IDs that are always the same for the same input. - Never use UUIDs as security tokens: use the
secretsmodule for cryptographic purposes. - Access different representations with
.hex,.int,.bytes, orstr()depending on your storage or transmission needs.