UUID v4 genereren in Python — uuid.uuid4() gids

·Backend Developer·Beoordeeld doorDmitri Volkov·Gepubliceerd

Gebruik de gratis UUID v4 Generator direct in je browser — geen installatie nodig.

UUID v4 Generator online uitproberen →

Telkens wanneer ik een botsingsbestendige identifier nodig heb voor een databaserij, API-trace of sessietoken, is het antwoord UUID v4 genereren in Python — één regel, nul afhankelijkheden: uuid.uuid4(). De ingebouwde uuid module van Python gebruikt os.urandom() voor cryptografisch veilige willekeurigheid. Voor een snelle UUID zonder code te schrijven werkt de online UUID v4 generator direct. Deze gids behandelt de attributen van het UUID-object, bulkgeneratie, JSON-serialisatie, databaseopslag, validatie, uuid-utils (~10× snellere Rust-backed drop-in) en de vier meest voorkomende fouten — alles met Python 3.8+.

Kernpunten
  • uuid.uuid4() is ingebouwd in Python's standaardbibliotheek — import uuid is alles wat je nodig hebt, geen pip install.
  • De returnwaarde is een uuid.UUID-object, geen string — gebruik str(), .hex of .bytes om de representatie te kiezen die past bij je opslaglaag.
  • UUID v4 gebruikt 122 willekeurige bits van os.urandom() — cryptografisch veilig, geen MAC-adres of tijdstempelblootstelling.
  • Voor high-throughput services is pip install uuid-utils een drop-in vervanging die ~10x sneller is, aangedreven door Rust.
  • Geef nooit uuid.uuid4 (zonder haakjes) direct door als standaardargument in een dataclass of Pydantic-model — het deelt dan één UUID over alle instanties.

Wat is UUID v4?

Een UUID (Universally Unique Identifier) is een 128-bit label opgemaakt als 32 hexadecimale cijfers verdeeld in vijf groepen door koppeltekens: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Versie 4 is de meest gebruikte variant: 122 van die 128 bits zijn willekeurig gegenereerd, en de overige 6 bits coderen de versie (4) en variant (RFC 4122). Er is geen tijdstempel en geen hostidentificator — de identifier is volledig ondoorzichtig en privacy-veilig. De kans dat twee onafhankelijk gegenereerde v4 UUID's botsen is zo klein dat het voor praktische doeleinden nooit voorkomt, zelfs niet in gedistribueerde systemen die miljoenen ID's per seconde genereren.

Before · Python
After · Python
event_id = "evt-" + str(random.randint(100000, 999999))  # fragile, not unique
event_id = str(uuid.uuid4())  # 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e

uuid.uuid4() — De standaardmanier om UUID v4 te genereren in Python

De uuid module maakt deel uit van Python's standaardbibliotheek. Het aanroepen van uuid.uuid4() geeft een uuid.UUID object terug met een volledige set attributen voor verschillende representaties. Converteren naar een string met str() geeft het canonieke koppelteken-formaat dat API's, databases en HTTP-headers verwachten.

Python 3.8+ — minimaal voorbeeld
import uuid

# Genereer een UUID v4
request_id = uuid.uuid4()

print(request_id)           # 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e
print(type(request_id))     # <class 'uuid.UUID'>
print(request_id.version)   # 4

# Converteer naar string voor JSON / HTTP-headers
print(str(request_id))      # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"
print(request_id.hex)       # "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e" (zonder koppeltekens)
print(request_id.bytes)     # b';...' (16 onbewerkte bytes)

Een veelvoorkomend praktijkpatroon is het koppelen van een UUID aan elk uitgaand API-verzoek zodat je logboeken kunt correleren over services heen. Hier is een minimale requests-sessiewrapper die een verse UUID in elke aanroep injecteert:

Python 3.8+ — trace-ID per verzoek
import uuid
import requests

def call_api(endpoint: str, payload: dict) -> dict:
    trace_id = str(uuid.uuid4())
    headers = {
        "X-Request-ID": trace_id,
        "Content-Type": "application/json",
    }
    response = requests.post(endpoint, json=payload, headers=headers, timeout=10)
    response.raise_for_status()
    return {"trace_id": trace_id, "data": response.json()}

# result["trace_id"] laat je het exacte verzoek terugvinden in alle servicelogboeken
result = call_api("https://api.example.com/v1/orders", {"product_id": "prod_7x2k", "qty": 3})
print(result["trace_id"])  # bijv. "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"

Bij het bulkgenereren van UUID's — bijvoorbeeld het vooraf vullen van een batch databaserijen — is een lijstcomprehensie idiomatisch en leesbaar:

Python 3.8+ — bulkgeneratie
import uuid

# Genereer ID's voor 1000 telemetriegebeurtenissen
event_ids = [str(uuid.uuid4()) for _ in range(1000)]
print(f"Generated {len(event_ids)} unique IDs")
print(event_ids[0])   # bijv. "a1c2e3f4-..."
print(event_ids[-1])  # elke keer een andere waarde

Heb je snel een UUID nodig zonder code te draaien? Gebruik de online UUID v4 generator om met één klik een verse waarde te kopiëren, of genereer er honderden tegelijk — handig voor het vullen van testdatabases of fixture-bestanden.

Opmerking:uuid.uuid4() roept intern os.urandom(16) aan, en stelt vervolgens bits 6–7 van byte 8 in op 10 (variant) en bits 12–15 van byte 6 op 0100 (versie 4). De overige 122 bits zijn willekeurig. Daarom kun je de versie niet vertrouwen tenzij je parseert met uuid.UUID().

UUID-objectattributen en representaties

Het uuid.UUID object biedt meerdere representaties van dezelfde 128-bit waarde. De juiste keuze voor je opslaglaag voorkomt stille datacorruptie en verspilde bytes.

Attribuut / Methode
Type
Beschrijving
uuid.UUID(hex=...)
UUID
Parseer een bestaande UUID vanuit een hex-string, met of zonder koppeltekens.
.hex
str
32-tekens kleine-letter hex-string zonder koppeltekens — compact opslagformaat.
.int
int
128-bit integer-representatie van de UUID — handig voor rekenkundige bewerkingen en sorteren.
.bytes
bytes
16-byte big-endian binaire representatie — meest efficiënte opslagformaat.
.bytes_le
bytes
16-byte little-endian binair — overeenkomstig de bytevolgorde van Microsoft GUID.
.fields
tuple
Zes-tuple van UUID-velden: (time_low, time_mid, time_hi_version, clock_seq_hi_variant, clock_seq_low, node).
.version
int | None
UUID-versienummer (1–5, of None voor niet-standaard UUID's).
.variant
str
UUID-variantstring — "specified in RFC 4122" voor standaard UUID's.
str(uuid_obj)
str
Canonieke 36-tekens string met vier koppeltekens: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
Python 3.8+ — alle representaties
import uuid

u = uuid.uuid4()

print(str(u))         # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"  (36 tekens)
print(u.hex)          # "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e"      (32 tekens, zonder koppeltekens)
print(u.bytes)        # b';Š...'                       (16 bytes, big-endian)
print(u.bytes_le)     # b'Š...'                       (16 bytes, little-endian)
print(u.int)          # 78823... (128-bit integer)
print(u.version)      # 4
print(u.variant)      # 'specified in RFC 4122'

# Heen-en-terug: reconstrueer vanuit string
reconstructed = uuid.UUID("3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e")
print(reconstructed == u)  # True (als u die waarde had)

Voor PostgreSQL met psycopg2 of asyncpg geef je het UUID object direct door — de driver regelt de toewijzing aan het native uuid kolomtype. Voor SQLite gebruik je str(u) (TEXT) of u.bytes (BLOB, 16 bytes vs 36 voor de string). Voor opslagefficiëntie op schaal is .bytes 55% kleiner dan de canonieke string.

UUID v4-strings valideren en parseren in Python

Telkens wanneer een UUID binnenkomt via gebruikersinvoer, een URL-padparameter of een upstream API, moet je deze valideren voordat je hem gebruikt als databasesleutel. De idiomatische aanpak is een constructiepoging met uuid.UUID() en het opvangen van ValueError. Je kunt ook afdwingen dat de inkomende waarde specifiek versie 4 is door .version te controleren.

Python 3.8+ — validatiehulpfunctie
import uuid

def parse_uuid4(raw: str) -> uuid.UUID:
    """
    Parseer en valideer een UUID v4-string.
    Gooit ValueError voor ongeldig formaat of verkeerde versie.
    """
    try:
        u = uuid.UUID(raw)
    except ValueError as exc:
        raise ValueError(f"Invalid UUID format: {raw!r}") from exc

    if u.version != 4:
        raise ValueError(f"Expected UUID v4, got v{u.version}: {raw!r}")

    return u

# Gebruik in een FastAPI / Flask route-handler
def get_order(order_id: str):
    try:
        uid = parse_uuid4(order_id)
    except ValueError as exc:
        return {"error": str(exc)}, 400

    # veilig om uid te gebruiken in een databasequery
    return {"order_id": str(uid), "status": "processing"}
Opmerking:uuid.UUID() accepteert strings met of zonder koppeltekens, en accepteert ook het urn:uuid:-voorvoegsel. Dus "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e" (zonder koppeltekens) en "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e" parseren beide naar hetzelfde object.

UUID v4 in JSON-payloads en API-responses

De JSON-standaard heeft geen UUID-type — een UUID in JSON is altijd een string. Dat betekent dat je het uuid.UUID object naar een string moet converteren voordat je het doorgeeft aan json.dumps(). De schoonste aanpak is een aangepaste JSONEncoder subklasse zodat je nooit str() aanroepen door je codebase hoeft te verspreiden.

Python 3.8+ — aangepaste JSONEncoder voor UUID
import json
import uuid
from datetime import datetime

class ApiEncoder(json.JSONEncoder):
    """Serialiseer UUID- en datetime-objecten in JSON-responses."""
    def default(self, obj):
        if isinstance(obj, uuid.UUID):
            return str(obj)
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

# Realistische API-response met geneste UUID's
api_response = {
    "request_id": uuid.uuid4(),
    "created_at": datetime(2026, 3, 14, 9, 41, 0),
    "order": {
        "id": uuid.uuid4(),
        "customer_id": uuid.uuid4(),
        "items": [
            {"product_id": uuid.uuid4(), "sku": "NVX-9000", "qty": 2},
        ],
    },
}

print(json.dumps(api_response, indent=2, cls=ApiEncoder))
# {
#   "request_id": "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e",
#   "created_at": "2026-03-14T09:41:00",
#   "order": {
#     "id": "a1c2e3f4-...",
#     ...
#   }
# }

Voor een eenmalige serialisatieaanroep is de default= hook eenvoudiger dan subklassen:

Python 3.8+ — default=-hook (eenmalig gebruik)
import json, uuid

event_id = uuid.uuid4()
payload = {"event_id": event_id, "action": "checkout"}

# Geef een callable door; wordt alleen aangeroepen voor typen die json niet kan verwerken
json_str = json.dumps(payload, default=str)
print(json_str)  # {"event_id": "3b1f8a9d-...", "action": "checkout"}

Bij het ontvangen van een response van een externe API, parseer je UUID-strings terug naar objecten zodat je code de volledige attribuutset en typeveiligheid krijgt:

Python 3.8+ — UUID parseren vanuit een API-response
import json
import uuid
import requests

def fetch_shipment(shipment_id: str) -> dict:
    """Haal een zending op en geef terug met getypeerde UUID-velden."""
    response = requests.get(
        f"https://api.logistics.example.com/v2/shipments/{shipment_id}",
        headers={"Accept": "application/json"},
        timeout=10,
    )
    response.raise_for_status()
    data = response.json()

    # Parseer de UUID-velden terug naar uuid.UUID-objecten
    try:
        data["id"] = uuid.UUID(data["id"])
        data["carrier_id"] = uuid.UUID(data["carrier_id"])
    except (KeyError, ValueError) as exc:
        raise RuntimeError(f"Malformed shipment response: {exc}") from exc

    return data

Om UUID-velden in een JSON-bestand op schijf bij te werken — bijvoorbeeld het roteren van een correlatie-ID in een configuratie- of seed-bestand — lees je, pas je aan en schrijf je atomair terug:

Python 3.8+ — JSON-bestand lezen, bijwerken en schrijven
import json, uuid

def rotate_correlation_id(path: str) -> str:
    """Vervang of voeg 'correlation_id' toe in een JSON-bestand. Geeft de nieuwe UUID terug."""
    try:
        with open(path) as f:
            data = json.load(f)
    except FileNotFoundError:
        data = {}
    except json.JSONDecodeError as exc:
        raise ValueError(f"Invalid JSON in {path!r}: {exc}") from exc

    new_id = str(uuid.uuid4())
    data["correlation_id"] = new_id

    with open(path, "w") as f:
        json.dump(data, f, indent=2)

    return new_id

Als je niet elke keer een script wilt draaien om een UUID uit een API-response te inspecteren, plak je hem direct in de UUID Decoder — die toont je de versie, variant en alle velden zonder code.

UUID v4 genereren via de commandoregel met Python

Python's uuid module biedt geen zelfstandige CLI-subcommando zoals python -m json.tool, maar een one-liner dekt hetzelfde gebruiksscenario. Deze zijn handig in shellscripts, CI-pipelines en wanneer je een wegwerpidentifier nodig hebt zonder een REPL te openen.

bash
# Enkele UUID v4
python3 -c "import uuid; print(uuid.uuid4())"
# 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e

# Geen-koppeltekens (hex) formaat — handig voor bestandsnamen en omgevingsvariabelen
python3 -c "import uuid; print(uuid.uuid4().hex)"
# 3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e

# Genereer 5 UUID's voor een batch seed-script
python3 -c "import uuid; [print(uuid.uuid4()) for _ in range(5)]"

# Gebruik in een shellvariabele
DEPLOY_ID=$(python3 -c "import uuid; print(uuid.uuid4())")
echo "Deploying with ID: $DEPLOY_ID"
Opmerking:Op macOS en de meeste Linux-distributies produceert uuidgen (een C-hulpprogramma) UUID v4-waarden en is sneller voor pure shellscripts. Gebruik de Python one-liner wanneer je al in een Python-gerichte omgeving werkt en consistentie wilt met hoe UUID's worden gegenereerd in je applicatiecode.

Hoge-prestatie UUID v4 met uuid-utils

De uuid.uuid4() van de standaardbibliotheek is snel genoeg voor de meeste toepassingen — bij een paar microseconden per aanroep verwerkt het gemakkelijk duizenden ID's per seconde. Als je UUID's genereert op het kritieke pad van een high-throughput service (bulkinvoegingen, per-event telemetrie op schaal, of het genereren van verzoek-ID's onder zware belasting), uuid-utils is een drop-in vervanging backed door Rust die benchmarkt op ongeveer 10x de snelheid van de standaardbibliotheek.

bash — install
pip install uuid-utils
Python 3.8+ — uuid-utils als drop-in vervanging
# uuid_utils is een drop-in vervanging voor de stdlib uuid-module
import uuid_utils as uuid

# Dezelfde API als stdlib
request_id = uuid.uuid4()
print(request_id)           # 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e
print(str(request_id))      # canonieke string
print(request_id.hex)       # hex zonder koppeltekens
print(request_id.version)   # 4

# Ondersteunt ook v7 (tijdgeordend, ideaal voor DB-primaire sleutels)
time_ordered_id = uuid.uuid7()
print(time_ordered_id)      # begint met huidig tijdstempelvoorvoegsel
Waarschuwing:De standaardmodus van uuid-utils geeft een eigen UUID-objecttype terug, dat in de meeste gevallen compatibel is met de standaardbibliotheek. Als je strikte isinstance(u, uuid.UUID)-controles vanuit de standaardbibliotheek nodig hebt, gebruik dan de compatibiliteitsmodus: import uuid_utils.compat as uuid. De compatibiliteitsmodus is iets langzamer dan de standaard, maar nog steeds sneller dan stdlib.

UUID v4 in dataclasses en Pydantic-modellen

Python-dataclasses en Pydantic-modellen ondersteunen beide UUID-velden native. Het sleutelpatroon bij het gebruik van UUID als automatisch gegenereerde standaardwaarde is het doorgeven van de functieverwijzing, niet een aanroepresultaat — anders deelt elke instantie dezelfde UUID.

Python 3.10+ — dataclass met UUID-standaard
from dataclasses import dataclass, field
import uuid

@dataclass
class WorkerJob:
    job_id: uuid.UUID = field(default_factory=uuid.uuid4)
    worker_id: str = "worker-01"
    payload: dict = field(default_factory=dict)

job1 = WorkerJob(payload={"task": "resize_image", "src": "uploads/img_4932.png"})
job2 = WorkerJob(payload={"task": "send_email",   "to":  "ops@example.com"})

print(job1.job_id)  # uniek per instantie
print(job2.job_id)  # verschilt van job1.job_id
print(job1.job_id == job2.job_id)  # False
Python 3.10+ — Pydantic v2-model met UUID
from pydantic import BaseModel, Field
import uuid

class OrderEvent(BaseModel):
    event_id: uuid.UUID = Field(default_factory=uuid.uuid4)
    order_id: uuid.UUID
    status: str
    amount_cents: int

event = OrderEvent(
    order_id=uuid.UUID("a1c2e3f4-5b6d-4e7f-8c9d-0a1b2c3d4e5f"),
    status="payment_confirmed",
    amount_cents=4995,
)

print(event.model_dump_json(indent=2))
# {
#   "event_id": "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e",
#   "order_id": "a1c2e3f4-5b6d-4e7f-8c9d-0a1b2c3d4e5f",
#   "status": "payment_confirmed",
#   "amount_cents": 4995
# }
# Pydantic v2 serialiseert uuid.UUID automatisch als string

Veelgemaakte fouten bij het genereren van UUID v4 in Python

Ik heb alle vier deze patronen gezien in code-reviews en productie-incidenten — ze zijn makkelijk over het hoofd te zien omdat ze niet direct een fout gooien.

uuid4 aanroepen zonder haakjes als standaardwaarde

Probleem: uuid.uuid4 (het functieobject) doorgeven als standaardwaarde in een dataclass of model zonder het in default_factory te wikkelen — Python evalueert de standaard eenmalig bij de klassedefinitie, waardoor alle instanties dezelfde UUID delen.

Oplossing: Gebruik default_factory=uuid.uuid4 in dataclasses of Field(default_factory=uuid.uuid4) in Pydantic, zodat per instantie een verse UUID wordt gegenereerd.

Before · Python
After · Python
@dataclass
class Session:
    # FOUT: eenmalig geëvalueerd, alle instanties delen deze UUID
    session_id: uuid.UUID = uuid.uuid4()
@dataclass
class Session:
    # CORRECT: factory wordt per instantie aangeroepen
    session_id: uuid.UUID = field(default_factory=uuid.uuid4)
Een UUID-object vergelijken met een gewone string

Probleem: uuid.UUID-objecten zijn niet gelijk aan gewone strings, dus session_id == '3b1f8a9d-...' geeft altijd False terug, ook als de waarde overeenkomt — waardoor zoekacties stil worden verbroken.

Oplossing: Vergelijk altijd UUID met UUID: wikkel de string in uuid.UUID() vóór het vergelijken, of converteer beide zijden naar str().

Before · Python
After · Python
# Geeft False terug zelfs als waarden overeenkomen
if record["session_id"] == "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e":
    revoke_session(record)
target = uuid.UUID("3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e")
if record["session_id"] == target:   # beide zijn uuid.UUID
    revoke_session(record)

# Of normaliseer alles naar strings op de grens:
if str(record["session_id"]) == str(target):
    revoke_session(record)
.hex opslaan in plaats van str() waardoor koppeltekens verloren gaan

Probleem: uuid_obj.hex geeft een 32-tekens string zonder koppeltekens. Als downstream code het canonieke 36-tekens formaat met koppeltekens verwacht (zoals de meeste API's en databases), wordt de waarde afgewezen of stil verkeerd geparseerd.

Oplossing: Gebruik str(uuid_obj) voor het canonieke 36-tekens formaat, tenzij je een expliciete vereiste hebt voor de compacte hex-vorm.

Before · Python
After · Python
# Slaat op "3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e" — zonder koppeltekens
payload = {"correlation_id": request_id.hex}
# Slaat op "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e" — standaardformaat
payload = {"correlation_id": str(request_id)}
random.random() of secrets.token_hex() gebruiken wanneer een UUID verwacht wordt

Probleem: random.random() is niet cryptografisch veilig, en secrets.token_hex(16) geeft een 32-tekens hex-string die geen geldige UUID is — downstream validators die uuid.UUID() aanroepen zullen een ValueError gooien.

Oplossing: Gebruik uuid.uuid4() wanneer het ontvangende systeem een UUID-geformatteerde identifier verwacht. Gebruik secrets.token_hex() alleen wanneer je expliciet een willekeurig token nodig hebt dat geen UUID-vorm heeft.

Before · Python
After · Python
import random, secrets

# Geen UUID — mislukt bij uuid.UUID()-validatie
request_id = secrets.token_hex(16)   # "a1b2c3d4e5f6..."
session_id = str(random.random())    # "0.8273..." — totaal verkeerd
import uuid

request_id = str(uuid.uuid4())  # "3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"
# Geldige UUID v4, cryptografisch veilig

UUID-generatiemethoden in Python — Snelle vergelijking

Alle onderstaande methoden produceren 128-bit identifiers, maar verschillen in entropiebron, privacykenmerken en of ze een externe installatie vereisen.

Methode
Bron
Uniciteit
Privacy-veilig
Aangepaste types
Snelheid
Installatie
uuid.uuid4()
Willekeurig (os.urandom)
2¹²² willekeurige bits
N.v.t.
Standaard
Ingebouwd
uuid.uuid1()
Tijdstempel + MAC
Tijd + host
❌ (MAC zichtbaar)
N.v.t.
Standaard
Ingebouwd
uuid.uuid3(name)
MD5-hash
Deterministisch
namespace+naam
Standaard
Ingebouwd
uuid.uuid5(name)
SHA-1-hash
Deterministisch
namespace+naam
Standaard
Ingebouwd
uuid_utils.uuid4()
Rust os.urandom
2¹²² willekeurige bits
N.v.t.
~10× sneller
pip install uuid-utils
secrets.token_hex(16)
os.urandom
128 willekeurige bits
N.v.t.
Snel
Ingebouwd
str(uuid.uuid4())
Willekeurig
2¹²² willekeurige bits
N.v.t.
Standaard
Ingebouwd

Gebruik uuid.uuid4() voor algemene unieke identifiers in webapplicaties, gedistribueerde systemen en database-primaire sleutels wanneer sorteerbaarheid niet vereist is. Gebruik uuid.uuid5() (of v3) voor deterministische ID's afgeleid van een bekende namespace en naam — bijvoorbeeld het genereren van een stabiel ID voor een canonieke URL. Schakel over naar uuid_utils.uuid7() wanneer je tijdgeordende ID's nodig hebt voor database-indexes (vermijdt pagina-splits in B-tree-indexes bij hoge invoegsnelheden). Grijp naar uuid_utils.uuid4() wanneer de ruwe generatiedoorvoer de bottleneck is.

UUID v4 vs UUID v7 — Welke moet je gebruiken?

De meest praktische vraag is of je UUID v4 of het nieuwere UUID v7 moet gebruiken voor database-primaire sleutels. Het korte antwoord: gebruik UUID v4 als standaard; schakel alleen over naar UUID v7 wanneer indexfragmentatie een gemeten probleem is.

UUID v4-waarden zijn volledig willekeurig, wat betekent dat invoegingen op willekeurige posities in een B-tree-index terechtkomen. Bij gematigde invoegsnelheden (honderden tot enkele duizenden per seconde) is dit prima — de index past in de buffergroep en willekeurige schrijfbewerkingen zijn goedkoop. Bij zeer hoge invoegsnelheden veroorzaakt willekeurige plaatsing frequente pagina-splits en cache-misses, wat de schrijfversterking vergroot en query's vertraagt.

UUID v7 bevat een millisecondeprecie Unix-tijdstempel in de meest significante bits, zodat rijen die dicht bij elkaar in de tijd worden ingevoegd ook dicht bij elkaar in de index terechtkomen. Dit geeft B-tree-indexes (PostgreSQL, MySQL, SQLite) gedrag dat dichter bij een auto-increment integer ligt: nieuwe rijen worden altijd aan het einde van de index toegevoegd, waardoor pagina-splits worden geëlimineerd. Het compromis is dat UUID v7 een tijdstempel codeert, wat de aanmaaktijd lekt — vermijd dit voor gebruikerszichtbare ID's waarbij aanmaaktijd gevoelig is.

In Python is UUID v7 nog niet in de standaardbibliotheek (vanaf Python 3.12). Genereer het met pip install uuid-utils en roep uuid_utils.uuid7() aan. Het geeft een object terug met dezelfde attribuutset als uuid.UUID, zodat migratie van v4 een één-regel wijziging is in de ID-fabriek.

Voor een éénklik-alternatief zonder Python-setup, plak je UUID-string in de UUID v4 generator en validator — die genereert, valideert en decodeert alle velden in de browser.

Veelgestelde vragen

Hoe genereer ik een UUID v4 in Python?

Roep uuid.uuid4() aan vanuit de ingebouwde uuid-module van Python. De functie geeft een UUID-object terug — converteer naar string met str() wanneer je een tekstrepresentatie nodig hebt. De module wordt meegeleverd met de standaardbibliotheek, dus pip install is niet nodig.

Python
import uuid

session_id = uuid.uuid4()
print(session_id)           # bijv. 3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e
print(str(session_id))      # dezelfde canonieke string
print(session_id.hex)       # 3b1f8a9d2c4e4f6a8b0d5e7c9f1a3d2e (zonder koppeltekens)

Wat is het verschil tussen uuid.uuid4() en str(uuid.uuid4())?

uuid.uuid4() geeft een UUID-object terug met attributen zoals .hex, .bytes, .int en .version. str(uuid.uuid4()) converteert dat object direct naar een 36-tekens canonieke string en gooit het object weg. Bewaar het object als je meerdere representaties nodig hebt; converteer naar string op de grens waar je de waarde doorgeeft aan een JSON-payload, database of HTTP-header.

Python
import uuid

u = uuid.uuid4()
print(type(u))          # <class 'uuid.UUID'>
print(u.version)        # 4
print(u.hex)            # 32-tekens hex, zonder koppeltekens
print(u.bytes)          # 16-byte binair
print(str(u))           # canonieke 36-tekens string met koppeltekens

Is uuid.uuid4() cryptografisch veilig?

Ja. Python's uuid.uuid4() gebruikt intern os.urandom(), dat leest uit de cryptografisch veilige willekeurige getallengenerator van het besturingssysteem (/dev/urandom op Linux/macOS, CryptGenRandom op Windows). De 122 willekeurige bits maken de kans op een botsing verwaarloosbaar voor elke realistische werklast. Verwar het niet met random.random(), dat niet cryptografisch veilig is.

Python
import uuid, os

# uuid4 roept intern os.urandom(16) aan
raw = os.urandom(16)
# uuid4 stelt de versie- en variantbits in voordat het teruggeeft
u = uuid.UUID(bytes=raw, version=4)
print(u)  # geldige v4 UUID van onbewerkte willekeurige bytes

Hoe valideer ik of een string een geldige UUID v4 is in Python?

Parseer met uuid.UUID() en controleer het .version-attribuut. Als de string geen geldige UUID is, gooit uuid.UUID() een ValueError — vang deze op om ongeldige invoer af te handelen. Dit valideert ook dat het formaat (koppeltekens, lengte) correct is.

Python
import uuid

def is_valid_uuid4(value: str) -> bool:
    try:
        u = uuid.UUID(value)
        return u.version == 4
    except ValueError:
        return False

print(is_valid_uuid4("3b1f8a9d-2c4e-4f6a-8b0d-5e7c9f1a3d2e"))  # True
print(is_valid_uuid4("geen-uuid"))                               # False
print(is_valid_uuid4("3b1f8a9d-2c4e-1f6a-8b0d-5e7c9f1a3d2e"))  # False (v1, niet v4)

Hoe sla ik UUID's op in een PostgreSQL- of SQLite-database vanuit Python?

Met PostgreSQL (via psycopg2 of asyncpg) geef je het UUID-object direct door — de driver past het aan naar het native UUID-type. Met SQLite, dat geen native UUID-type heeft, sla je op als TEXT met str(uuid_obj) of als BLOB met uuid_obj.bytes. SQLAlchemy heeft een UUID-kolomtype dat dit automatisch over alle dialecten afhandelt.

Python
import uuid
import sqlite3

conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE events (id TEXT PRIMARY KEY, name TEXT)")

event_id = uuid.uuid4()
conn.execute("INSERT INTO events VALUES (?, ?)", (str(event_id), "user_signup"))
conn.commit()

row = conn.execute("SELECT * FROM events").fetchone()
# Reconstrueer UUID-object vanuit opgeslagen string
retrieved_id = uuid.UUID(row[0])
print(retrieved_id.version)  # 4

Kan ik meerdere UUID's tegelijk genereren in Python?

Ja — gebruik een lijstcomprehensie of een generator. Elke aanroep van uuid.uuid4() is onafhankelijk en gegarandeerd een unieke waarde te produceren. Voor bulkgeneratie waarbij doorvoer belangrijk is, is uuid-utils (Rust-backed) ongeveer 10x sneller dan de standaardbibliotheek.

Python
import uuid

# Genereer 5 unieke trace-ID's voor een batchverzoek
trace_ids = [str(uuid.uuid4()) for _ in range(5)]
for tid in trace_ids:
    print(tid)
# Elke regel is een aparte UUID v4

Gerelateerde tools

  • UUID v4 GeneratorGenereer UUID v4-waarden direct in de browser — geen Python-omgeving nodig. Kopieer één waarde of genereer er honderden tegelijk.
  • UUID v7 GeneratorGenereer tijdgeordende UUID v7-waarden — sorteerbaar op aanmaaktijd, ideaal voor database-primaire sleutels waarbij indexfragmentatie een rol speelt.
  • UUID DecoderInspecteer elke UUID — versie, variant, tijdstempel (v1/v7) en knooppuntvelden — zonder zelf een parser te schrijven.
  • JWT DecoderDecodeer en inspecteer JWT-tokens, die vaak UUID-subject-claims (sub) of jti-identificatoren bevatten naast sessie-UUID's.
MS
Maria SantosBackend Developer

Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.

DV
Dmitri VolkovTechnisch beoordelaar

Dmitri is a DevOps engineer who relies on Python as his primary scripting and automation language. He builds internal tooling, CI/CD pipelines, and infrastructure automation scripts that run in production across distributed teams. He writes about the Python standard library, subprocess management, file processing, encoding utilities, and the practical shell-adjacent Python that DevOps engineers use every day.