Skip to main content

Searching...

Tools
Articles
View All Results

Developer Lab · Python

Generate UUID in Python

Python ships a uuid module in its standard library - no pip install, no dependencies. uuid.uuid4() gives you a CSPRNG-backed v4 UUID in one line.

Quick Reference

Function Version Sortable Use Case
uuid.uuid4() v4 No General purpose - session IDs, API keys, record IDs
uuid.uuid1() v1 Yes Legacy systems, Cassandra timeuuid
uuid.uuid5() v5 No Deterministic - same input always gives same UUID
uuid.UUID(str) any - Parse and validate an existing UUID string

Primary Implementation

Production Ready
python
import uuid

# UUID v4 - random, CSPRNG-backed, zero dependencies
id = uuid.uuid4()
print(id)
# → f47ac10b-58cc-4372-a567-0e02b2c3d479

# As a plain string
id_str = str(uuid.uuid4())

# As a 32-char hex string (no hyphens)
id_hex = uuid.uuid4().hex
# → f47ac10b58cc4372a5670e02b2c3d479

# As bytes (16 bytes)
id_bytes = uuid.uuid4().bytes

# Generate multiple
ids = [str(uuid.uuid4()) for _ in range(5)]

# Parse and validate an existing UUID string
try:
    parsed = uuid.UUID("f47ac10b-58cc-4372-a567-0e02b2c3d479")
    print(parsed.version)  # → 4
except ValueError:
    print("Invalid UUID")

All UUID Versions

UUID v4 - Random (recommended default)

python
import uuid
# 122 bits of randomness - use for anything that just needs a unique ID
id = uuid.uuid4()
print(str(id))  # → "550e8400-e29b-41d4-a716-446655440000"

UUID v5 - Deterministic / Namespace-based

python
import uuid
# SHA-1 hash of namespace + name - same inputs always produce the same UUID
# Useful for deduplication and content-addressable IDs
id = uuid.uuid5(uuid.NAMESPACE_DNS, "example.com")
print(str(id))  # → always "cfbff0d1-9375-5685-968c-48ce8b15ae17"

# Custom namespace
my_ns = uuid.uuid4()  # generate once, store it
record_id = uuid.uuid5(my_ns, "user:42")

UUID v1 - Timestamp + MAC (legacy)

python
import uuid
# Encodes current timestamp + MAC address - sortable but leaks host info
# Only use for Cassandra timeuuid or legacy system compatibility
id = uuid.uuid1()
print(id.time)  # 100-nanosecond intervals since Oct 15, 1582

Real-World Use Cases

1. Django / SQLAlchemy model primary key

python
import uuid
from django.db import models

class Order(models.Model):
    # Django natively supports UUIDField
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    created_at = models.DateTimeField(auto_now_add=True)

# SQLAlchemy equivalent
from sqlalchemy import Column, String
from sqlalchemy.dialects.postgresql import UUID as PG_UUID

class Product(Base):
    __tablename__ = "products"
    id = Column(PG_UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)

2. FastAPI request tracing

python
import uuid
from fastapi import FastAPI, Request
import logging

app = FastAPI()
logger = logging.getLogger(__name__)

@app.middleware("http")
async def add_request_id(request: Request, call_next):
    request_id = str(uuid.uuid4())
    request.state.request_id = request_id
    response = await call_next(request)
    response.headers["X-Request-ID"] = request_id
    logger.info(f"[{request_id}] {request.method} {request.url.path}")
    return response

3. Deduplication with UUID v5

python
import uuid

# Idempotent event ID - same event always gets the same UUID
EVENT_NAMESPACE = uuid.UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8")

def event_id(source: str, event_type: str, timestamp: str) -> str:
    key = f"{source}:{event_type}:{timestamp}"
    return str(uuid.uuid5(EVENT_NAMESPACE, key))

# Calling twice with same args returns the same UUID - safe to retry
id1 = event_id("payments", "charge.created", "2026-05-01T12:00:00Z")
id2 = event_id("payments", "charge.created", "2026-05-01T12:00:00Z")
assert id1 == id2  # True

Common Mistakes

Passing uuid.uuid4 instead of uuid.uuid4() as a default

In Django/SQLAlchemy, pass the function reference default=uuid.uuid4 (no parentheses). With parentheses, every row gets the same UUID generated at class definition time.

Storing as string when the DB supports a native UUID type

PostgreSQL has a native UUID column type that stores 16 bytes. Storing as VARCHAR(36) wastes 20 bytes per row and slows index lookups.

Using uuid.uuid1() in production web services

UUID v1 embeds your server's MAC address. This leaks network interface information and can be a privacy/security concern. Use v4 unless you specifically need Cassandra timeuuid.

How It Works

uuid.uuid4() calls os.urandom(16) internally to get 16 random bytes from the OS CSPRNG, then sets the version bits (bits 12–15 of octet 6 = 0100) and variant bits (bits 6–7 of octet 8 = 10).

The result is a uuid.UUID object. Call str() on it for the standard hyphenated format, .hex for 32-char no-hyphen, or .bytes for raw 16-byte binary.

The uuid.UUID object is immutable, hashable, and comparable - you can use it directly as a dict key or in a set.

Output Formats

str(id)

f47ac10b-58cc-4372-a567-0e02b2c3d479

id.hex

f47ac10b58cc4372a5670e02b2c3d479

id.bytes (16 bytes)

b'\xf4z\xc1\x0bX\xccCr\xa5g\x0e\x02\xb2\xc3\xd4y'

id.int

324716517733474852975027497220825710713

Best Practices, Performance, and Security

Best practices

Use uuid.uuid4() as the default for all new code.

Pass the UUID object around - only convert to string at the boundary (DB write, API response).

Use uuid.uuid5() for deterministic IDs - great for idempotent event processing.

Performance

CPython generates roughly 1–3 million UUIDs/second on modern hardware. The bottleneck is os.urandom() - a syscall on every call.

For bulk generation, the uuid module is sufficient. If you need higher throughput, generate a large buffer with os.urandom(16 * n) and slice it manually.

Security

Entropy source: os.urandom() - maps to /dev/urandom on Linux/macOS and CryptGenRandom on Windows. Cryptographically secure.

Suitable for session tokens, CSRF tokens, and API keys. Do not use uuid.uuid1() for security-sensitive IDs.

Installation

UUID v4 (standard library)

bash
# No installation needed - standard library

Available in Python 2.5+ and all Python 3.x versions. No pip install required.

Frequently Asked Questions

How do I generate a UUID in Python?

Python ships a uuid module in its standard library, so there is nothing to install. uuid.uuid4() returns a random v4 UUID and str() gives the canonical form. Python 3 has no built-in v7, so use a package such as uuid6 or uuid-utils for time-ordered UUIDs.

Is uuid.uuid4() cryptographically secure?

Yes. uuid.uuid4() uses the platform CSPRNG (operating system secure random source), suitable for session tokens, API keys, and idempotency keys. Do not use non-cryptographic random sources for security-sensitive identifiers.

What is the difference between UUID v4 and v7 in Python?

UUID v4 (uuid.uuid4() or equivalent) is fully random and not sortable. UUID v7 embeds a millisecond timestamp for chronological sorting (RFC 9562). Use v4 for general-purpose IDs; use v7 for database primary keys at scale.

Do I need to install a package for UUID generation in Python?

No additional package is required for basic v4 generation in Python. Check the Installation section for version-specific notes.

How do I validate a UUID string in Python?

Use the platform's UUID parse/validation function, or test against the RFC 4122 regex: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i. Always validate external input at API boundaries.

Should I use UUIDs as database primary keys in Python applications?

UUIDs work well as primary keys for distributed systems. Prefer native UUID/BINARY(16) column types over VARCHAR(36). For very large tables, consider UUID v7 for better B-tree insert locality.

Can I generate UUIDs in Python without a network connection?

Yes. UUID generation uses local OS entropy sources and does not require network access. Each call is independent and thread-safe on modern platforms.

What output formats are available in Python?

The standard hyphenated lowercase string (36 chars) is the default. Most APIs also support 32-char hex (no hyphens) and 16-byte binary formats. Use string format for APIs and binary for database storage.

What RFC standards apply to Python UUID generation?

Version 4 UUIDs follow RFC 4122. UUID v7 follows RFC 9562 (May 2024). Ensure your chosen method produces compliant version and variant bits.

When should I avoid UUID v1?

Avoid UUID v1 in security-sensitive contexts - it embeds MAC address and timestamp information. Prefer v4 (uuid.uuid4() or equivalent) unless you need legacy Cassandra timeuuid compatibility.

Key definitions

UUID
128-bit universally unique identifier, usually shown as 36 hex characters with hyphens.
CSPRNG
Cryptographically secure pseudo-random number generator - the entropy source behind secure UUID generation.
RFC 4122
IETF standard defining UUID versions 1 through 5. Version 4 is random.
RFC 9562
IETF standard adding UUID versions 6, 7, and 8. Version 7 is time-ordered.