Benchmarking UUID Generation in Python: Speed vs. Randomness Trade-offs

    December 19, 2023
    10 min read
    Tutorial
    Technical deep-dive
    uuid
    performance
    code-examples

    UUIDs are everywhere — in databases, logs, APIs, and analytics platforms. But not all UUIDs are created equal, especially when it comes to speed vs. security.

    In this article, we benchmark several UUID generation methods in Python, show you their trade-offs, and help you pick the best one for your needs.


    🧬 The Contenders

    Python’s built-in uuid module provides several ways to generate UUIDs:

    • uuid1() — time and MAC address-based
    • uuid4() — fully random (cryptographically secure)
    • uuid5() — SHA-1 + namespace-based (deterministic)

    We'll also include:

    • secrets.token_hex(16) — fast secure random string (not a UUID)
    • os.urandom(16) — raw CSPRNG output

    🧪 Benchmark Setup

    We used timeit with 1 million iterations per function on Python 3.11.

    python
    import timeit
    import uuid
    import secrets
    import os
    
    iterations = 1_000_000
    
    results = {
        "uuid1": timeit.timeit("uuid.uuid1()", setup="import uuid", number=iterations),
        "uuid4": timeit.timeit("uuid.uuid4()", setup="import uuid", number=iterations),
        "uuid5": timeit.timeit("uuid.uuid5(uuid.NAMESPACE_DNS, 'example.com')", setup="import uuid", number=iterations),
        "secrets.token_hex": timeit.timeit("secrets.token_hex(16)", setup="import secrets", number=iterations),
        "os.urandom": timeit.timeit("os.urandom(16)", setup="import os", number=iterations),
    }

    ⚡ Performance Results

    MethodTotal Time (1M runs)Per Call (µs)
    uuid.uuid1()~1.0 sec~1.0 µs
    uuid.uuid4()~1.3 sec~1.3 µs
    uuid.uuid5()~5.8 sec~5.8 µs
    secrets.token_hex()~1.0 sec~1.0 µs
    os.urandom(16)~0.9 sec~0.9 µs

    > 💡 These numbers will vary slightly by hardware, OS, and Python version — but the trend is consistent.


    🛡️ Security + Randomness Considerations

    `uuid.uuid1()`

    • Not cryptographically safe
    • Contains MAC address + timestamp
    • Useful for internal tracing, but never expose it in public APIs

    `uuid.uuid4()`

    • Cryptographically secure (uses os.urandom)
    • Standard choice for unique, unguessable IDs
    • Slightly slower than uuid1(), but safer

    `uuid.uuid5()`

    • Deterministic — same input → same UUID
    • Good for namespacing, e.g. DNS, resource IDs
    • Slowest of the bunch due to hashing

    `secrets.token_hex(16)`

    • Not a UUID, but cryptographically strong
    • Great for compact tokens
    • Faster than uuid4() and just as secure

    `os.urandom(16)`

    • Raw secure entropy
    • Use if you want a custom 16-byte ID in binary or hex

    ✍️ Code Examples

    UUIDv4 (Recommended Default)

    python
    import uuid
    user_id = uuid.uuid4()

    UUIDv5 (Deterministic)

    python
    import uuid
    resource_id = uuid.uuid5(uuid.NAMESPACE_URL, "https://example.com/resource")

    Secure Token (Not a UUID, but fast + safe)

    python
    import secrets
    api_token = secrets.token_hex(16)  # 32-char hex string

    ⚙️ When to Use What

    Use CaseBest Option
    Public API IDuuid.uuid4()
    Trace ID in logsuuid.uuid1()
    Deterministic ID (by name)uuid.uuid5()
    Fast, secure tokensecrets.token_hex()
    Custom binary IDos.urandom(16)

    🧠 Pro Tips

    • Always use uuid4() for general-purpose ID generation
    • Avoid uuid1() in untrusted contexts — it leaks timestamp + MAC
    • Store UUIDs as BINARY(16) in databases for speed/space efficiency
    • If you don’t need UUID format, secrets.token_hex(16) is faster and shorter
    • Never use random.random() for IDs — it’s not secure

    🧪 Bonus: Parallel Generation

    Want to speed up ID creation? Use multiprocessing:

    python
    from multiprocessing import Pool
    import uuid
    
    def gen():
        return uuid.uuid4()
    
    with Pool(4) as p:
        results = p.map(lambda _: gen(), range(1_000_000))

    Python’s uuid4() is thread-safe and uses system-level CSPRNG, so it scales well in multi-core environments.


    Final Thoughts

    UUIDs are deceptively simple — but choosing the right generation method can have big implications for performance, security, and uniqueness at scale.

    Unless you have special needs (e.g., determinism, MAC tracing), `uuid4()` is the default winner.

    Use it well, log it liberally, and never — ever — fake it with random().

    Generate Your Own UUIDs

    Ready to put this knowledge into practice? Try our UUID generators:

    Generate a Single UUID

    Create a UUID with our fast, secure generator

    Bulk UUID Generator

    Need multiple UUIDs? Generate them in bulk

    Summary

    This article benchmarks Python’s UUID generation methods (v1, v4, v5) to compare their speed, randomness, and practical use cases. It includes performance data, security insights, and real-world recommendations for APIs, logs, and scalable systems.

    TLDR;

    This article compares UUID generation methods in Python using real benchmarks.

    Key takeaways:

    • uuid.uuid1() is fast but leaks time and MAC address — not safe for public use
    • uuid.uuid4() is slower but cryptographically secure and widely recommended
    • Alternatives like secrets.token_hex(16) are fast and safe when UUID format isn't required

    Use UUIDv4 for most cases, UUIDv1 for internal logs, and consider secrets for compact tokens in custom ID formats.

    Cookie Consent

    We use cookies to enhance your experience on our website. By accepting, you agree to the use of cookies in accordance with our Privacy Policy.