Czym jest UUID? 128-bitowa struktura, wersje i praktyczne zastosowania
Za każdym razem, gdy rejestrujesz się w jakiejś usłudze, dla twojego konta tworzony jest unikalny identyfikator. Każde żądanie API niesie ze sobą trace ID. Każdy wiersz w rozproszonej bazie danych potrzebuje klucza głównego, który nie zderzy się z kluczami generowanymi na innych maszynach. Rozwiązanie stojące za tym wszystkim? UUID — Universally Unique Identifier.
Ten przewodnik wyjaśnia, czym są UUID, jak są zbudowane, co każda wersja robi pod maską oraz kiedy ich używać (a kiedy unikać).
UUID w pigułce
UUID to 128-bitowy (16-bajtowy) identyfikator zaprojektowany tak, aby był globalnie unikalny bez konieczności korzystania z centralnego rejestru. Zapisuje się go jako 32 cyfry szesnastkowe w kanonicznym formacie 8-4-4-4-12:
550e8400-e29b-41d4-a716-446655440000
|------| |--| |--| |--| |----------|
8 hex 4 4 4 12 hex
To 32 znaki hex + 4 myślniki = łącznie 36 znaków. Myślniki są czysto kosmetyczne — nie niosą żadnych danych.
Najważniejsze fakty:
- 128 bitów = 2¹²⁸ ≈ 3,4 × 10³⁸ możliwych wartości
- Standaryzowany przez RFC 9562 (maj 2024, zastępuje RFC 4122)
- W ekosystemach Microsoftu nazywany również GUID (Globally Unique Identifier) — ten sam format, inna nazwa
- Wspierany natywnie przez PostgreSQL (typ
uuid), MySQL (BINARY(16)lubCHAR(36)) oraz praktycznie każdy język programowania
Anatomia UUID
Każdy UUID koduje dwa pola metadanych w stałych pozycjach bitowych, niezależnie od wersji:
550e8400-e29b-41d4-a716-446655440000
^ ^
| |
Version-┘ └-Variant
Pole wersji (bity 48–51)
- cyfra hex (pierwsza cyfra trzeciej grupy) identyfikuje wersję UUID:
| Cyfra hex | Wersja | Metoda |
|---|---|---|
1 | v1 | Timestamp + adres MAC |
3 | v3 | Hash MD5 z namespace + nazwa |
4 | v4 | Kryptograficznie losowy |
5 | v5 | Hash SHA-1 z namespace + nazwa |
6 | v6 | Przeporządkowany timestamp (RFC 9562) |
7 | v7 | Unix timestamp + losowość (RFC 9562) |
8 | v8 | Niestandardowy / zależny od implementacji |
Pole wariantu (bity 64–65)
- cyfra hex (pierwsza cyfra czwartej grupy) identyfikuje wariant. Dla UUID zgodnych z RFC 4122/9562 pierwsze bity to
10, co oznacza, że ta cyfra hex zawsze przyjmuje wartość8,9,alubb.
Przykładowy rozkład
550e8400-e29b-41d4-a716-446655440000
↑ ↑
4 → v4 a → RFC 4122 variant
This is a UUID v4 (random), RFC 4122/9562 variant.
Wersje UUID — wyjaśnienie
UUID v1: timestamp + adres MAC
UUID v1 był pierwotnym projektem. Koduje:
- 60-bitowy timestamp — odstępy 100-nanosekundowe od 15 października 1582 roku (reforma kalendarza gregoriańskiego)
- 14-bitową sekwencję zegara — licznik monotoniczności zapobiegający duplikatom przy cofnięciu zegara
- 48-bitowy node — zwykle adres MAC maszyny
| Timestamp | Ver | Clk |Var| Node (MAC) |
| 60 bits | 4b | 14b |2b | 48 bits |
Problemy:
- Ujawnia czas wygenerowania oraz tożsamość sprzętu (ryzyko prywatności)
- Adresy MAC można sfałszować, co podważa unikalność
- Epoka roku 1582 jest myląca i wymaga konwersji
Werdykt: wycofany przez RFC 9562. W identyfikatorach opartych na czasie używaj v7.
UUID v3: oparty na nazwie z MD5 (deterministyczny)
UUID v3 oblicza hash z namespace UUID oraz łańcucha nazwy za pomocą MD5. Te same dane wejściowe zawsze produkują ten sam UUID.
import uuid
# namespace = DNS, name = "example.com"
print(uuid.uuid3(uuid.NAMESPACE_DNS, "example.com"))
# → "9073926b-929f-31c2-abc9-fad77ae3e8eb" (always this value)
Zdefiniowane są cztery standardowe namespace’y:
- 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
Werdykt: funkcjonalny, ale lepiej wybrać v5 — SHA-1 jest silniejszy niż MD5.
UUID v4: losowy — najpopularniejszy
UUID v4 wypełnia 122 bity kryptograficznie bezpiecznymi danymi losowymi (pozostałe 6 bitów jest zarezerwowane na pola wersji i wariantu).
| Random | Ver | Random |Var| Random |
| 48 bits | 4b | 12 bits |2b | 62 bits |
Przy 2¹²² ≈ 5,3 × 10³⁶ możliwych wartościach prawdopodobieństwo kolizji jest astronomicznie niskie. Aby osiągnąć 50% szansę na choć jedną kolizję, potrzeba około 2,71 × 10¹⁸ UUID — czyli 2,71 tryliona (10¹⁸ w polskiej długiej skali = angielski quintillion; uwaga: angielski „trillion” 10¹² to po polsku „bilion”, nie „trylion”).
// Every modern browser and Node.js supports this
const id = crypto.randomUUID();
console.log(id); // → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
Mocne strony: prostota, prywatność, uniwersalne wsparcie, brak potrzeby koordynacji.
Słaba strona: losowy rozkład powoduje fragmentację indeksów B-tree, gdy v4 jest używany jako klucz główny w bazie danych. Dla zastosowań intensywnie korzystających z bazy danych warto rozważyć v7.
UUID v5: oparty na nazwie z SHA-1 (deterministyczny)
Identyczny jak v3, ale używa SHA-1 zamiast MD5. Te same dane wejściowe zawsze produkują ten sam UUID.
import uuid
print(uuid.uuid5(uuid.NAMESPACE_DNS, "example.com"))
# → "cfbff0d1-9375-5685-968c-48ce8b15ae17" (always this value)
Zastosowania:
- Generowanie stabilnych ID na podstawie URL-i lub nazw DNS
- Klucze do magazynów typu content-addressable
- Powtarzalne fixture’y testowe
Ważne: v3 i v5 NIE są przeznaczone do celów bezpieczeństwa. Są deterministyczne — każdy, kto zna namespace i nazwę, może odtworzyć UUID.
UUID v7: Unix timestamp + losowość (rekomendowany dla nowych projektów)
UUID v7 to najnowsza wersja, wprowadzona w RFC 9562 (maj 2024). Koduje:
- 48-bitowy Unix timestamp w milisekundach — monotonicznie rosnący
- 74 bity kryptograficznej losowości
| Unix timestamp (ms) | Ver | rand_a |Var| rand_b |
| 48 bits | 4b | 12 bits |2b | 62 bits |
Oznacza to, że UUID v7 są naturalnie sortowane według czasu utworzenia — nowsze UUID są zawsze leksykograficznie większe od starszych. Ta właściwość czyni je idealnymi jako klucze główne w bazie danych, gdzie indeksy B-tree pozostają sekwencyjne, zamiast losowo się fragmentować.
import { v7 as uuidv7 } from "uuid";
const id1 = uuidv7(); // generated at T₁
const id2 = uuidv7(); // generated at T₂ (T₂ > T₁)
console.log(id1 < id2); // → true (lexicographic comparison)
Dlaczego to ma znaczenie dla baz danych: sekwencyjna natura v7 redukuje liczbę podziałów stron indeksu nawet o 90% w porównaniu do v4, co przekłada się na szybsze inserty, mniejsze indeksy i lepszą wydajność cache.
UUID a GUID — czym się różnią?
Funkcjonalnie niczym. GUID (Globally Unique Identifier) to nazwa stosowana przez Microsoft na UUID, używana w Windows, .NET, COM oraz SQL Server. Format jest identyczny: 128 bitów, hex w układzie 8-4-4-4-12.
Jedyna różnica kosmetyczna: narzędzia Microsoftu czasami wyświetlają GUID-y wielkimi literami i w nawiasach klamrowych:
UUID: 550e8400-e29b-41d4-a716-446655440000
GUID: {550E8400-E29B-41D4-A716-446655440000}
Jeżeli ktoś pyta o „różnicę między UUID a GUID”, odpowiedź brzmi: branding.
Specjalne wartości UUID
RFC 9562 definiuje dwa specjalne UUID:
| Nazwa | Wartość | Cel |
|---|---|---|
| Nil UUID | 00000000-0000-0000-0000-000000000000 | Reprezentuje brak wartości (jak null) |
| Max UUID | ffffffff-ffff-ffff-ffff-ffffffffffff | Znacznik granicy lub wartość wartownik |
Nigdy nie używaj ich jako rzeczywistych identyfikatorów — z definicji nie są unikalne.
Prawdopodobieństwo kolizji: problem urodzin
„Problem urodzin” pozwala obliczyć, ile UUID trzeba wygenerować, zanim kolizja stanie się prawdopodobna. Dla UUID v4 (122 losowe bity):
| Wygenerowane UUID | Prawdopodobieństwo kolizji |
|---|---|
| 1 milion | ~10⁻²² (praktycznie niemożliwe) |
| 1 miliard | ~10⁻¹⁶ (nadal zaniedbywalne) |
| 2,71 × 10¹⁸ | 50% (granica „urodzinowa”) |
Dla porównania: gdyby generować 1 miliard UUID na sekundę, osiągnięcie 50% szansy na pojedynczą kolizję zajęłoby 86 lat. W praktyce awarie sprzętu, błędy w oprogramowaniu i promieniowanie kosmiczne są bardziej prawdopodobnymi przyczynami duplikatu niż matematyka UUID v4.
Wzór: p(n) ≈ n² / (2 × 2¹²²)
Jak walidować UUID
Poprawny UUID pasuje do tego wzorca regex (bez rozróżniania wielkości liter):
^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
Sprawdza on:
- Format hex 8-4-4-4-12
- Cyfra wersji w zakresie 1–7 (pozycja 15)
- Nibble wariantu zaczyna się od 8, 9, a lub b (pozycja 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
Generowanie UUID w różnych językach
JavaScript / TypeScript
// Browser & Node.js — built-in v4
crypto.randomUUID();
// npm uuid package — supports v1, v3, v4, v5, v7
import { v4, v7 } from "uuid";
v4(); // random
v7(); // time-ordered
Python
import uuid
uuid.uuid4() # random
uuid.uuid5(uuid.NAMESPACE_DNS, "example.com") # deterministic
# uuid.uuid7() planned for Python 3.14+
Go
import "github.com/google/uuid"
uuid.New() // v4 random
uuid.Must(uuid.NewV7()) // v7 time-ordered
Java
import java.util.UUID;
UUID.randomUUID(); // v4 random
// UUID v7: use com.fasterxml.uuid or java.util.UUID in JDK 21+
SQL (PostgreSQL)
-- v4 (PostgreSQL 13+)
SELECT gen_random_uuid();
-- v7 (PostgreSQL 18+)
SELECT uuidv7();
Najczęstsze zastosowania
Klucze główne w bazach danych
UUID pozwalają generować ID gdziekolwiek — w aplikacji, na kliencie, na brzegu sieci — bez zaglądania do bazy danych. Umożliwia to architektury offline-first i upraszcza systemy rozproszone. Dla najlepszej wydajności indeksu używaj v7, a jeśli kolejność nie ma znaczenia — v4.
Śledzenie żądań API
Każdemu żądaniu API przypisuj UUID w punkcie wejścia (gateway, load balancer). Przekazuj je do wszystkich usług w dół przepływu w nagłówku takim jak X-Request-ID. Dzięki temu korelowanie logów między mikrousługami staje się trywialne.
Klucze idempotencji
API używają UUID jako kluczy idempotencji, aby ponownie wysłane żądania nie tworzyły duplikatów zasobów. Klient generuje UUID przed pierwszą próbą i wysyła ten sam UUID przy ponowieniach.
Identyfikatory sesji
UUID zapewniają wystarczającą unikalność, aby zapobiec kolizjom sesji w dużych bazach użytkowników. W odróżnieniu od liczb auto-increment nie da się ich enumerować — atakujący nie odgadnie poprawnych ID sesji przez zwiększanie liczby.
Magazyny content-addressable
UUID v5 generuje deterministyczne ID na podstawie zawartości. Dla tego samego wejścia zawsze otrzymasz ten sam UUID — przydatne przy deduplikacji, cache’owaniu i powtarzalnych buildach.
Kwestie bezpieczeństwa
UUID NIE są tokenami bezpieczeństwa
UUID są zaprojektowane pod kątem unikalności, a nie tajności. Kluczowe problemy:
- UUID v1 ujawnia timestamp generacji oraz adres MAC
- UUID v4 ma 122 losowe bity, ale przewidywalną strukturę (bity wersji i wariantu są stałe)
- UUID v3/v5 są deterministyczne — każdy, kto zna namespace i nazwę, może odtworzyć UUID
Do tokenów bezpieczeństwa, kluczy API lub sekretów sesyjnych używaj dedykowanego CSPRNG z 128+ bitami czystej losowości:
// For security tokens — NOT a UUID, but fully random
const token = Array.from(crypto.getRandomValues(new Uint8Array(32)))
.map(b => b.toString(16).padStart(2, "0"))
.join("");
UUID v7 ujawnia czas utworzenia
Pierwsze 48 bitów UUID v7 koduje timestamp utworzenia w milisekundach. Każdy, kto otrzyma UUID v7, może odczytać moment jego powstania:
const hex = "01906b5e-4a3e-7234-8f56-b8c12d4e5678".replace(/-/g, "").slice(0, 12);
new Date(parseInt(hex, 16));
// → 2024-07-01T12:34:56.000Z
Jeśli czas utworzenia jest informacją wrażliwą, używaj v4.
Nie używaj UUID do zapobiegania enumeracji
Choć UUID trudniej zgadnąć niż sekwencyjne liczby całkowite, nie powinny być jedynym mechanizmem kontroli dostępu. Zawsze egzekwuj kontrole autoryzacji — nie polegaj na nieprzejrzystości URL.
Często zadawane pytania
Dlaczego w UUID są myślniki?
Myślniki w formacie 8-4-4-4-12 służą wyłącznie czytelności dla człowieka. Nie niosą żadnych danych i są ignorowane podczas parsowania. Niektóre systemy przechowują UUID bez myślników (32 znaki hex), co jest równie poprawne.
Czy dwa UUID mogą być takie same?
Teoretycznie tak, praktycznie nie. Dla UUID v4 ze 122 losowymi bitami prawdopodobieństwo wygenerowania dwóch identycznych UUID wynosi w przybliżeniu 1 na 5,3 × 10³⁶ dla dowolnej pary. Przy realnych tempach generowania jest bardziej prawdopodobne, że trafi cię piorun w trakcie wygranej w lotto, niż że napotkasz kolizję UUID.
Czy UUID są sekwencyjne?
Tylko niektóre wersje. UUID v1, v6 i v7 zawierają timestamp i sortują się chronologicznie. UUID v4 jest całkowicie losowy, bez żadnej kolejności. UUID v3 i v5 są deterministyczne, ale nie uporządkowane.
Ile miejsca zajmuje UUID?
- Binarnie: 16 bajtów (128 bitów) — najbardziej wydajna forma przechowywania
- String (z myślnikami): 36 bajtów (ASCII)
- String (bez myślników): 32 bajty (ASCII)
Większość baz danych przechowuje UUID wewnętrznie w formacie binarnym. Natywny typ uuid w PostgreSQL zajmuje dokładnie 16 bajtów.
UUID czy auto-increment dla kluczy głównych?
Auto-increment jest prostszy w aplikacjach z jedną bazą danych (mniejszy, szybszy, sekwencyjny). UUID jest lepszy w systemach rozproszonych (generowanie wszędzie, brak koordynacji, bezpieczne łączenie). Jeśli wybierasz UUID, preferuj v7 dla najlepszej wydajności bazy danych.
Czym jest RFC 9562?
RFC 9562, opublikowany w maju 2024 roku, to najnowszy standard UUID. Zastępuje RFC 4122 i formalnie wprowadza wersje UUID 6, 7 oraz 8. Wycofuje v1 na rzecz v6/v7 oraz definiuje wartości nil i max UUID. Jeżeli implementujesz generowanie lub walidację UUID, RFC 9562 jest miarodajnym źródłem.
Czy mogę używać UUID w różnych językach programowania?
Tak. Format UUID (128-bitowy, hex 8-4-4-4-12) jest niezależny od języka. UUID wygenerowany w JavaScripcie zostanie poprawnie odczytany w Pythonie, Go, Javie czy dowolnym innym języku ze wsparciem dla UUID. Ta interoperacyjność to jedna z największych zalet UUID.
Generuj, dekoduj i waliduj UUID natychmiast w naszym narzędziu Generator UUID — wspiera v1, v4, v5 i v7 z generowaniem wsadowym, w 100% w przeglądarce.
Wybierasz między wersjami UUID dla swojego kolejnego projektu? Praktyczny przewodnik wyboru z benchmarkami baz danych i przykładami kodu — porównanie UUID v4 vs v7 vs ULID vs Snowflake — pojawi się wkrótce.