The uuid module in the Python standard library generates universally unique identifiers (UUIDs), which are 128-bit values typically displayed as 36-character strings like 550e8400-e29b-41d4-a716-446655440000. Use UUIDs as primary keys in databases, identifiers for API resources, or tracing IDs in distributed systems where you cannot rely on a single auto-increment counter.
import uuid
new_id = uuid.uuid4()
print(new_id) # 550e8400-e29b-41d4-a716-446655440000
print(str(new_id)) # 550e8400-e29b-41d4-a716-446655440000
print(new_id.hex) # 550e8400e29b41d4a716446655440000uuid.uuid4() generates a random UUID. The string representation includes dashes at positions 8, 13, 18, and 23. .hex returns the same value as a 32-character string without dashes.
UUID versions
Not every UUID is generated the same way, and picking the right version affects both privacy and database performance. The uuid module supports several versions, each with a different generation strategy.
import uuid
print("v1:", uuid.uuid1()) # v1: f47ac10b-58cc-11e8-ae4d-8c8590a91e3b
print("v4:", uuid.uuid4()) # v4: 550e8400-e29b-41d4-a716-446655440000| Version | Method | Description |
|---|---|---|
| UUIDv1 | uuid.uuid1() | Based on timestamp and MAC address. Unique but reveals when and where the ID was created. |
| UUIDv4 | uuid.uuid4() | Fully random. Does not reveal timing or machine information. The safest choice for most applications. |
| UUIDv3 | uuid.uuid3(ns, name) | MD5 hash of a namespace UUID and a name. Deterministic: same input always produces the same UUID. |
| UUIDv5 | uuid.uuid5(ns, name) | SHA-1 hash of a namespace UUID and a name. Same as v3 but with a stronger hash. |
| UUIDv7 | uuid.uuid7() | Time-ordered with random bits. Added in Python 3.14. Good for database primary keys. |
For most applications, use UUIDv4. It is the simplest, safest, and most widely compatible option.
UUIDv7: time-ordered identifiers
UUIDv7, available since Python 3.14, combines a Unix timestamp with random bits. The timestamp prefix means UUIDs generated close together sort in chronological order, which improves database index performance compared to fully random UUIDv4.
import uuid
import time
for _ in range(3):
print(uuid.uuid7())
time.sleep(0.001)Generating three UUIDs a millisecond apart shows the pattern clearly, since the leading segment of each value tracks the advancing timestamp while the rest stays effectively random:
018f5d80-7a3b-7000-8000-000000000001
018f5d80-7a3b-7000-8000-000000000002
018f5d80-7a3b-7000-8000-000000000003The first part of each UUID increments because the timestamp advances. Unlike UUIDv1, UUIDv7 does not expose the MAC address. It is designed specifically for database primary keys where insertion-order locality matters.
If you are using an older Python version, UUIDv7 is not available from the standard library. Use UUIDv4 or a third-party library.
Deterministic UUIDs with v3 and v5
UUIDv3 and UUIDv5 produce the same UUID every time for the same namespace and name. This is useful when you need to derive a stable identifier from existing data.
import uuid
NAMESPACE_URL = uuid.UUID("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
article_id = uuid.uuid5(NAMESPACE_URL, "https://example.com/articles/42")
print(article_id) # de470051-1183-5a53-a13d-d33bc219f294The same namespace and name always produce the same UUID. This is useful for content-addressable identifiers or generating IDs from stable input like URLs or filenames.
Predefined namespace UUIDs are available:
| Constant | Value |
|---|---|
| uuid.NAMESPACE_DNS | 6ba7b810-9dad-11d1-80b4-00c04fd430c8 |
| uuid.NAMESPACE_URL | 6ba7b811-9dad-11d1-80b4-00c04fd430c8 |
| uuid.NAMESPACE_OID | 6ba7b812-9dad-11d1-80b4-00c04fd430c8 |
| uuid.NAMESPACE_X500 | 6ba7b814-9dad-11d1-80b4-00c04fd430c8 |
Use UUIDv5 over UUIDv3 when possible. SHA-1 is a stronger hash than MD5 and produces equally deterministic results.
Parsing UUID strings
Convert strings to UUID objects with the UUID constructor.
import uuid
raw = "550e8400-e29b-41d4-a716-446655440000"
uid = uuid.UUID(raw)
print(uid.version) # 4
print(uid.variant) # specified in RFC 4122
print(uid.bytes) # b'U\x0e\x84\x00\xe2\x9bA\xd4\xa7\x16DfUD\x00\x00'uid.version tells you which UUID version was used. uid.variant identifies the UUID layout. uid.bytes returns the raw 16 bytes.
The constructor accepts several formats:
uuid.UUID("550e8400-e29b-41d4-a716-446655440000") # standard
uuid.UUID("550e8400e29b41d4a716446655440000") # hex
uuid.UUID("{550e8400-e29b-41d4-a716-446655440000}") # with braces
uuid.UUID("urn:uuid:550e8400-e29b-41d4-a716-446655440000") # URNUUIDs as database primary keys
UUIDs are commonly used as primary keys instead of auto-increment integers. They have tradeoffs.
Advantages of UUID primary keys:
- You can generate the ID in application code before inserting, so you know the ID immediately.
- No collisions when merging data from multiple sources or databases.
- They do not reveal information about how many records exist (unlike sequential integers).
Disadvantages:
- UUIDs are 16 bytes versus 4 or 8 bytes for integers, so indexes are larger.
- Random UUIDs (v4) cause index fragmentation in B-tree databases, slowing inserts.
- UUIDs are not human-friendly for debugging or customer support references.
If the index fragmentation is a concern, use UUIDv7 (Python 3.14+) for time-ordered IDs that maintain database index performance.
Practical example: generating IDs for uploaded files
Generate a unique filename for each uploaded file to prevent name collisions.
import uuid
from pathlib import Path
def unique_filename(original_name):
ext = Path(original_name).suffix
return f"{uuid.uuid4().hex}{ext}"
names = ["report.pdf", "report.pdf", "photo.jpg"]
for name in names:
print(unique_filename(name))Both uploads named report.pdf get a different, unpredictable filename even though they share the original name, because each call to uuid4() generates a fresh random value:
a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.pdf
f7e8d9c0b1a293847576655443322101.pdf
1234567890abcdef1234567890abcdef.jpgEach file gets a unique hex name, avoiding collisions even when users upload files with identical names. The original extension is preserved for correct MIME type detection.
Common mistakes
Using UUIDv1 when privacy matters. UUIDv1 includes the machine's MAC address and the creation timestamp. Anyone who sees the UUID can determine when and (potentially) where it was generated. Use UUIDv4 for privacy-sensitive applications.
Relying on UUIDs for security through obscurity. UUIDs are identifiers, not secrets. If a UUID appears in a URL or API response, assume it is public. Do not use UUIDs as authentication tokens. For secure tokens, use the secrets module.
Calling uuid4 without storing the result. Every call to uuid.uuid4() returns a new random value. Store the result in a variable; do not call uuid.uuid4() multiple times expecting the same value.
Forgetting that UUIDv3/v5 are deterministic. Same inputs produce the same UUID. This is by design but can be surprising if you expect randomness.
Rune AI
Key Insights
- Use
uuid.uuid4()for random, universally unique identifiers. - Use
uuid.uuid7()(Python 3.14+) for time-ordered UUIDs that sort well in databases. - Convert UUIDs to strings with
str(uuid)or to hex withuuid.hex. - Parse UUID strings with
uuid.UUID('...'). - UUIDs are 128-bit values; the collision probability for v4 is effectively zero.
- Avoid UUIDv1 when you do not want to expose the MAC address and timestamp.
Frequently Asked Questions
Which UUID version should I use?
Are UUIDs guaranteed to be unique?
Can I convert a UUID to and from a string?
Conclusion
The uuid module is the standard way to generate unique identifiers in Python. Use uuid.uuid4() for random IDs that do not reveal any information, and uuid.uuid7() when you need time-ordered IDs for database performance. UUIDs are ideal for distributed systems where you cannot rely on a central auto-increment counter.
More in this topic
Format Dates and Times in Python
Learn how to use strftime and strptime to format dates as strings and parse date strings into Python datetime objects.
What Is the Python Standard Library?
Learn what the Python standard library is, why it matters, and how to use its built-in modules without installing anything extra.
Encode and Decode Base64 Data in Python
Learn how to use Python's base64 module to encode binary data as text and decode Base64 strings back to bytes.