UUID erklärt: 128-Bit-Struktur, Versionen und Einsatzgebiete
Jedes Mal, wenn du dich bei einem Dienst registrierst, wird ein eindeutiger Bezeichner für dein Konto erstellt. Jede API-Anfrage trägt eine Trace-ID. Jede Zeile in einer verteilten Datenbank braucht einen Primärschlüssel, der nicht mit Schlüsseln kollidiert, die auf anderen Maschinen erzeugt wurden. Die Lösung hinter all dem? UUID — Universally Unique Identifier.
Dieser Leitfaden erklärt, was UUIDs sind, wie sie aufgebaut sind, was jede Version intern macht und wann man sie einsetzen (oder vermeiden) sollte.
UUID auf einen Blick
Eine UUID ist ein 128-Bit (16-Byte) Bezeichner, der so konzipiert ist, dass er weltweit eindeutig ist, ohne eine zentrale Vergabestelle. Sie wird als 32 Hexadezimalziffern im kanonischen 8-4-4-4-12-Format geschrieben:
550e8400-e29b-41d4-a716-446655440000
|------| |--| |--| |--| |----------|
8 hex 4 4 4 12 hex
Das sind 32 Hex-Zeichen + 4 Bindestriche = 36 Zeichen insgesamt. Die Bindestriche sind rein kosmetisch und tragen keine Daten.
Wichtige Fakten:
- 128 Bits = 2¹²⁸ ≈ 3,4 × 10³⁸ mögliche Werte
- Standardisiert durch RFC 9562 (Mai 2024, ersetzt RFC 4122)
- Auch GUID (Globally Unique Identifier) genannt im Microsoft-Ökosystem (gleiches Format, anderer Name)
- Nativ unterstützt von PostgreSQL (
uuid-Typ), MySQL (BINARY(16)oderCHAR(36)) und praktisch jeder Programmiersprache
Aufbau einer UUID
Jede UUID codiert zwei Metadatenfelder an festen Bitpositionen, unabhängig von der Version:
550e8400-e29b-41d4-a716-446655440000
^ ^
| |
Version-┘ └-Variante
Versionsfeld (Bits 48–51)
Die 13. Hex-Ziffer (erste Ziffer der dritten Gruppe) identifiziert die UUID-Version:
| Hex-Ziffer | Version | Methode |
|---|---|---|
1 | v1 | Zeitstempel + MAC-Adresse |
3 | v3 | MD5-Hash aus Namespace + Name |
4 | v4 | Kryptografisch zufällig |
5 | v5 | SHA-1-Hash aus Namespace + Name |
6 | v6 | Umgeordneter Zeitstempel (RFC 9562) |
7 | v7 | Unix-Zeitstempel + Zufall (RFC 9562) |
8 | v8 | Benutzerdefiniert / implementierungsspezifisch |
Variantenfeld (Bits 64–65)
Die 17. Hex-Ziffer (erste Ziffer der vierten Gruppe) identifiziert die Variante. Bei RFC 4122/9562 UUIDs beginnen die ersten Bits mit 10, was bedeutet, dass diese Hex-Ziffer immer 8, 9, a oder b ist.
Beispiel-Aufschlüsselung
550e8400-e29b-41d4-a716-446655440000
↑ ↑
4 → v4 a → RFC 4122 Variante
Dies ist eine UUID v4 (zufällig), RFC 4122/9562 Variante.
UUID-Versionen erklärt
Version 1: Zeitstempel + MAC-Adresse
UUID v1 war das ursprüngliche Design. Sie codiert:
- 60-Bit-Zeitstempel: 100-Nanosekunden-Intervalle seit dem 15. Oktober 1582 (der Gregorianischen Kalenderreform)
- 14-Bit-Taktsequenz: Monotonie-Zähler zur Vermeidung von Duplikaten bei Taktrücksetzung
- 48-Bit-Knoten: typischerweise die MAC-Adresse der Maschine
| Zeitstempel | Ver | Takt |Var| Knoten (MAC) |
| 60 Bits | 4b | 14b |2b | 48 Bits |
Probleme:
- Offenbart Erstellungszeitpunkt und Hardware-Identität (Datenschutzrisiko)
- MAC-Adressen können gefälscht werden, was die Eindeutigkeit untergräbt
- Die Epoche von 1582 ist verwirrend und erfordert Umrechnung
Empfehlung: Von RFC 9562 als veraltet erklärt. Nutze stattdessen v7 für zeitbasierte UUIDs.
Version 3: MD5-basiert (deterministisch)
UUID v3 hasht eine Namespace-UUID und einen Namensstring mit MD5. Die gleichen Eingaben erzeugen immer die gleiche UUID.
import uuid
# namespace = DNS, name = "example.com"
print(uuid.uuid3(uuid.NAMESPACE_DNS, "example.com"))
# → "9073926b-929f-31c2-abc9-fad77ae3e8eb" (immer dieser Wert)
Vier Standard-Namespaces sind definiert:
- DNS:
6ba7b810-9dad-11d1-80b4-00c04fd430c8 - URL:
6ba7b811-9dad-11d1-80b4-00c04fd430c8 - OID:
6ba7b812-9dad-11d1-80b4-00c04fd430c8 - X.500:
6ba7b814-9dad-11d1-80b4-00c04fd430c8
Empfehlung: Funktioniert, aber v5 ist vorzuziehen, da SHA-1 stärker als MD5 ist.
Version 4: Zufällig — die beliebteste
UUID v4 füllt 122 Bits mit kryptografisch sicheren Zufallsdaten (die übrigen 6 Bits sind für Versions- und Variantenfelder reserviert).
| Zufall | Ver | Zufall |Var| Zufall |
| 48 Bits | 4b | 12 Bits |2b | 62 Bits |
Mit 2¹²² ≈ 5,3 × 10³⁶ möglichen Werten ist die Kollisionswahrscheinlichkeit astronomisch gering. Um eine 50%ige Chance auf mindestens eine Kollision zu erreichen, bräuchte man ungefähr 2,71 × 10¹⁸ UUIDs, also 2,71 Trillionen.
// Jeder moderne Browser und Node.js unterstützt dies
const id = crypto.randomUUID();
console.log(id); // → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
Stärken: Einfach, privat, universell unterstützt, keine Koordination nötig.
Schwäche: Die zufällige Verteilung verursacht B-Tree-Index-Fragmentierung bei Nutzung als Datenbank-Primärschlüssel. Für datenbankintensive Anwendungsfälle lohnt sich ein Blick auf v7.
Version 5: SHA-1-basiert (deterministisch)
Identisch mit v3, verwendet aber SHA-1 statt MD5. Die gleichen Eingaben erzeugen immer die gleiche UUID.
import uuid
print(uuid.uuid5(uuid.NAMESPACE_DNS, "example.com"))
# → "cfbff0d1-9375-5685-968c-48ce8b15ae17" (immer dieser Wert)
Einsatzgebiete:
- Stabile IDs aus URLs oder DNS-Namen generieren
- Schlüssel für inhaltsadressierte Speicherung
- Reproduzierbare Test-Fixtures
Wichtig: v3 und v5 sind NICHT für Sicherheitszwecke gedacht. Sie sind deterministisch. Jeder, der den Namespace und den Namen kennt, kann die UUID reproduzieren.
Version 7: Unix-Zeitstempel + Zufall (empfohlen für neue Projekte)
UUID v7 ist die neueste Version, eingeführt in RFC 9562 (Mai 2024). Sie codiert:
- 48-Bit-Unix-Zeitstempel in Millisekunden, monoton steigend
- 74 Bits kryptografischer Zufälligkeit
| Unix-Zeitstempel (ms) | Ver | rand_a |Var| rand_b |
| 48 Bits | 4b | 12 Bits |2b | 62 Bits |
Das bedeutet, v7-UUIDs sind natürlich nach Erstellungszeit sortiert. Neuere UUIDs sind immer lexikografisch größer als ältere. Diese Eigenschaft macht sie ideal für Datenbank-Primärschlüssel, wo B-Tree-Indizes sequenziell bleiben, anstatt zufällig zu fragmentieren.
import { v7 as uuidv7 } from "uuid";
const id1 = uuidv7(); // erzeugt bei T₁
const id2 = uuidv7(); // erzeugt bei T₂ (T₂ > T₁)
console.log(id1 < id2); // → true (lexikografischer Vergleich)
Warum das für Datenbanken wichtig ist: Die sequenzielle Eigenschaft von v7 reduziert Index-Page-Splits um bis zu 90 % im Vergleich zu v4, was zu schnelleren Einfügungen, kleineren Indizes und besserer Cache-Performance führt.
UUID vs GUID — Was ist der Unterschied?
Es gibt keinen funktionalen Unterschied. GUID (Globally Unique Identifier) ist Microsofts Bezeichnung für UUID, verwendet in Windows, .NET, COM und SQL Server. Das Format ist identisch: 128 Bits, 8-4-4-4-12 Hex.
Der einzige kosmetische Unterschied: Microsoft-Tools zeigen GUIDs manchmal in Großbuchstaben mit geschweiften Klammern an:
UUID: 550e8400-e29b-41d4-a716-446655440000
GUID: {550E8400-E29B-41D4-A716-446655440000}
Wenn jemand nach dem „Unterschied zwischen UUID und GUID” fragt, lautet die Antwort: Branding.
Spezielle UUID-Werte
RFC 9562 definiert zwei spezielle UUIDs:
| Name | Wert | Zweck |
|---|---|---|
| Nil UUID | 00000000-0000-0000-0000-000000000000 | Repräsentiert die Abwesenheit eines Wertes (wie null) |
| Max UUID | ffffffff-ffff-ffff-ffff-ffffffffffff | Grenzwertmarkierung oder Sentinel-Wert |
Verwende diese niemals als tatsächliche Bezeichner. Sie sind per Definition nicht eindeutig.
Kollisionswahrscheinlichkeit: Das Geburtstagsparadoxon
Das „Geburtstagsparadoxon” berechnet, wie viele UUIDs man braucht, bevor eine Kollision wahrscheinlich wird. Für UUID v4 (122 zufällige Bits):
| Erzeugte UUIDs | Kollisionswahrscheinlichkeit |
|---|---|
| 1 Million | ~10⁻²² (praktisch unmöglich) |
| 1 Milliarde | ~10⁻¹⁶ (immer noch vernachlässigbar) |
| 2,71 × 10¹⁸ | 50 % (die „Geburtstagsgrenze”) |
Zum Vergleich: Wenn du 1 Milliarde UUIDs pro Sekunde erzeugst, würde es 86 Jahre dauern, um eine 50%ige Chance auf eine einzige Kollision zu erreichen. In der Praxis sind Hardwarefehler, Softwarebugs und kosmische Strahlung alle wahrscheinlicher als eine UUID-v4-Kollision.
Die Formel: p(n) ≈ n² / (2 × 2¹²²)
Wie man eine UUID validiert
Eine gültige UUID entspricht diesem Regex-Muster (Groß-/Kleinschreibung ignoriert):
^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
Dies prüft:
- Das 8-4-4-4-12 Hex-Format
- Die Versionsziffer ist 1–7 (Position 15)
- Das Varianten-Nibble beginnt mit 8, 9, a oder b (Position 20)
function isValidUUID(str) {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str);
}
isValidUUID("550e8400-e29b-41d4-a716-446655440000"); // → true
isValidUUID("not-a-uuid"); // → false
UUIDs in jeder Programmiersprache erzeugen
JavaScript / TypeScript
// Browser & Node.js — eingebaut v4
crypto.randomUUID();
// npm uuid-Paket — unterstützt v1, v3, v4, v5, v7
import { v4, v7 } from "uuid";
v4(); // zufällig
v7(); // zeitgeordnet
Python
import uuid
uuid.uuid4() # zufällig
uuid.uuid5(uuid.NAMESPACE_DNS, "example.com") # deterministisch
# uuid.uuid7() geplant für Python 3.14+
Go
import "github.com/google/uuid"
uuid.New() // v4 zufällig
uuid.Must(uuid.NewV7()) // v7 zeitgeordnet
Java
import java.util.UUID;
UUID.randomUUID(); // v4 zufällig
// UUID v7: verwende com.fasterxml.uuid oder java.util.UUID in JDK 21+
SQL (PostgreSQL)
-- v4 (PostgreSQL 13+)
SELECT gen_random_uuid();
-- v7 (PostgreSQL 18+)
SELECT uuidv7();
Häufige Anwendungsfälle
Datenbank-Primärschlüssel
UUIDs ermöglichen es, IDs überall zu generieren (in der Anwendung, auf dem Client, am Edge) ohne einen Datenbank-Roundtrip. Das ermöglicht Offline-first-Architekturen und vereinfacht verteilte Systeme. Nutze v7 für die beste Index-Performance oder v4, wenn dir die Reihenfolge egal ist.
API-Request-Tracing
Weise jeder API-Anfrage am Eintrittspunkt (Gateway, Load Balancer) eine UUID zu. Leite sie durch alle nachgelagerten Dienste in einem Header wie X-Request-ID weiter. So lassen sich Logs über Microservices hinweg mühelos korrelieren.
Idempotenzschlüssel
APIs verwenden UUIDs als Idempotenzschlüssel, um sicherzustellen, dass wiederholte Anfragen keine doppelten Ressourcen erzeugen. Der Client generiert eine UUID vor dem ersten Versuch und sendet dieselbe UUID bei Wiederholungen.
Session-Bezeichner
UUIDs bieten ausreichende Eindeutigkeit, um Session-Kollisionen über große Nutzerbasen hinweg zu verhindern. Im Gegensatz zu Auto-Increment-Ganzzahlen können sie nicht aufgezählt werden. Ein Angreifer kann keine gültigen Session-IDs erraten, indem er eine Zahl hochzählt.
Inhaltsadressierte Speicherung
UUID v5 generiert deterministische IDs aus Inhalten. Bei gleicher Eingabe erhält man immer dieselbe UUID, nützlich für Deduplizierung, Caching und reproduzierbare Builds.
Sicherheitsaspekte
UUIDs sind KEINE Sicherheitstoken
UUIDs sind für Eindeutigkeit konzipiert, nicht für Geheimhaltung.
- UUID v1 offenbart den Erstellungszeitpunkt und die MAC-Adresse
- UUID v4 hat 122 zufällige Bits, aber eine vorhersagbare Struktur (Versions-/Variantenbits sind fest)
- UUID v3/v5 sind deterministisch. Jeder, der Namespace und Name kennt, kann die UUID reproduzieren
Für Sicherheitstoken, API-Schlüssel oder Session-Geheimnisse verwende einen dedizierten CSPRNG mit 128+ Bits reiner Zufälligkeit:
// Für Sicherheitstoken — KEINE UUID, aber voll zufällig
const token = Array.from(crypto.getRandomValues(new Uint8Array(32)))
.map(b => b.toString(16).padStart(2, "0"))
.join("");
UUID v7 offenbart die Erstellungszeit
Die ersten 48 Bits einer UUID v7 codieren den Erstellungszeitstempel in Millisekunden. Jeder, der eine v7-UUID erhält, kann extrahieren, wann sie erstellt wurde:
const hex = "01906b5e-4a3e-7234-8f56-b8c12d4e5678".replace(/-/g, "").slice(0, 12);
new Date(parseInt(hex, 16));
// → 2024-07-01T12:34:56.000Z
Falls die Erstellungszeit sensible Information ist, verwende stattdessen v4.
UUIDs nicht zur Aufzählungsverhinderung nutzen
Obwohl UUIDs schwerer zu erraten sind als sequenzielle Ganzzahlen, sollten sie nicht dein einziger Zugangskontrollmechanismus sein. Setze immer Autorisierungsprüfungen durch. Verlasse dich nicht auf URL-Verschleierung.
Häufig gestellte Fragen
Warum gibt es Bindestriche in UUIDs?
Die Bindestriche im 8-4-4-4-12-Format dienen ausschließlich der menschlichen Lesbarkeit. Sie tragen keine Daten und werden beim Parsen ignoriert. Manche Systeme speichern UUIDs ohne Bindestriche (32 Hex-Zeichen), was ebenso gültig ist.
Können zwei UUIDs jemals gleich sein?
Theoretisch ja, praktisch nein. Bei UUID v4 mit 122 zufälligen Bits beträgt die Wahrscheinlichkeit, zwei identische UUIDs zu generieren, ungefähr 1 zu 5,3 × 10³⁶ für ein beliebiges Paar. Bei realen Erzeugungsraten wirst du eher vom Blitz getroffen, während du im Lotto gewinnst, als eine UUID-Kollision zu erleben.
Sind UUIDs sequenziell?
Nur einige Versionen. UUID v1, v6 und v7 enthalten Zeitstempel und sortieren sich chronologisch. UUID v4 ist vollständig zufällig ohne Ordnung. UUID v3 und v5 sind deterministisch, aber nicht geordnet.
Wie viel Speicherplatz benötigt eine UUID?
- Binär: 16 Bytes (128 Bits), die effizienteste Speicherung
- String (mit Bindestrichen): 36 Bytes (ASCII)
- String (ohne Bindestriche): 32 Bytes (ASCII)
Die meisten Datenbanken speichern UUIDs intern im Binärformat. PostgreSQL’s nativer uuid-Typ verwendet genau 16 Bytes.
Soll ich UUID oder Auto-Increment für Primärschlüssel verwenden?
Auto-Increment ist einfacher für Einzeldatenbank-Anwendungen (kleiner, schneller, sequenziell). UUID ist besser für verteilte Systeme (überall generierbar, keine Koordination, merge-sicher). Bei UUID-Nutzung bevorzuge v7 für die beste Datenbank-Performance.
Was ist RFC 9562?
RFC 9562, veröffentlicht im Mai 2024, ist der neueste UUID-Standard. Er ersetzt RFC 4122 und führt formal die UUID-Versionen 6, 7 und 8 ein. Er erklärt v1 zugunsten von v6/v7 als veraltet und definiert die Nil- und Max-UUID-Werte. Wenn du UUID-Erzeugung oder -Validierung implementierst, ist RFC 9562 die maßgebliche Referenz.
Kann ich UUIDs über verschiedene Programmiersprachen hinweg verwenden?
Ja. Das UUID-Format (128-Bit, 8-4-4-4-12 Hex) ist sprachunabhängig. Eine in JavaScript erzeugte UUID wird in Python, Go, Java oder jeder anderen Sprache mit UUID-Unterstützung korrekt geparst. Diese Interoperabilität ist eine der größten Stärken von UUIDs.
Siehe auch: UUID-Generator (v1, v4, v5, v7 mit Batch-Generierung) | UUID v4 vs v7 vs ULID vs Snowflake Vergleich