Generator ULID
Generuje leksykograficznie sortowalne unikalne identyfikatory
Kliknij Generuj, aby utworzyć ULID
Czym jest ULID?
ULID (Universally Unique Lexicographically Sortable Identifier) to 128-bitowy format identyfikatora zaprojektowany tak, aby być zarówno unikalnym, jak i naturalnie sortowalnym. W odróżnieniu od UUID v4, który jest całkowicie losowy, ULID osadza uniksowy znacznik czasu z dokładnością do milisekundy w swoich wysokich bitach — zapewniając, że identyfikatory generowane później sortują się po identyfikatorach generowanych wcześniej.
ULID-y są kodowane przy użyciu alfabetu Crockford's Base32, produkując kompaktowy 26-znakowy ciąg bezpieczny dla URL, bez rozróżniania wielkości liter i wolny od wizualnie niejednoznacznych znaków.
Specyfikacja ULID została stworzona przez Alizaina Feerastę i jest szeroko stosowana w systemach rozproszonych, event sourcingu i kluczach głównych baz danych, gdzie liczy się zarówno unikalność, jak i porządek czasowy. ULID-y nie są standardem IETF — są specyfikacją społecznościową dostępną na ulid.github.io.
Struktura ULID
ULID ma 128 bitów szerokości, podzielonych na dwa komponenty:
| Znacznik czasu | Losowy |
|---|---|
| 01ARZ3NDEK | TSVE4RRFFQ69G5FAV |
| 48 bitów — uniksowy znacznik czasu w milisekundach. Koduje czas generowania z precyzją 1ms. Obejmuje daty do roku 10889. | 80 bitów — kryptograficznie bezpieczne losowe dane. Generowane od nowa dla każdego ULID (chyba że używany jest tryb monotoniczności). |
Kodowany jako 26 znaków Crockford Base32: pierwsze 10 znaków reprezentuje znacznik czasu, ostatnie 16 znaków reprezentuje komponent losowy.
Alfabet Crockford Base32
ULID-y używają kodowania Crockford's Base32, które korzysta z 32 ze 36 znaków alfanumerycznych. Alfabet to: 0123456789ABCDEFGHJKMNPQRSTVWXYZ
Cztery znaki są celowo wykluczone:
IiLsą wykluczone — łatwo mylone z cyfrą1Ojest wykluczone — łatwo mylone z cyfrą0Ujest wykluczone — unika przypadkowych nieprzyzwoitych słów w generowanych identyfikatorach- Kodowanie jest
bez rozróżniania wielkości liter—01ARZ3NDEKTSV4RRFFQ69G5FAVi01arz3ndektsv4rrffq69g5favto ten sam ULID
Crockford Base32 jest bardziej wydajny niż szesnastkowy (32 symbole vs 16) i bardziej czytelny dla człowieka niż Base64 (bez znaków + / =, bez rozróżniania wielkości liter).
ULID a UUID
ULID-y i UUID-y reprezentują 128-bitowe identyfikatory, ale znacznie różnią się kodowaniem i celami projektowymi:
| Właściwość | ULID | UUID |
|---|---|---|
| Format | Crockford Base32 | Szesnastkowy z myślnikami |
| Długość | 26 znaków | 36 znaków |
| Znacznik czasu | 48-bitowy uniksowy ms | Brak (v4) lub 48-bitowy ms (v7) |
| Sortowalny | Tak — leksykograficzny | Nie (v4) / Tak (v7) |
| Bezpieczny dla URL | Tak (tylko alfanumeryczny) | Tak (z myślnikami) |
| Zależności | Wymaga biblioteki | Natywny (crypto.randomUUID) |
| Obsługa bazy danych | Przechowuj jako CHAR(26) lub BINARY(16) | Natywny typ kolumny UUID |
| Specyfikacja | Specyfikacja społecznościowa (ulid.github.io) | RFC 4122 / RFC 9562 |
Jeśli jesteś już w ekosystemie UUID (kolumny uuid PostgreSQL, REST API, ORM z obsługą UUID), UUID v7 jest zazwyczaj lepszym wyborem niż ULID. Jeśli wolisz bardziej przyjazne dla człowieka kodowanie i kontrolujesz cały stos, ULID jest doskonałym wyborem.
ULID a nanoid
Zarówno ULID, jak i nanoid produkują krótkie, bezpieczne dla URL identyfikatory, ale mają różne cele projektowe:
| Właściwość | ULID | NanoID |
|---|---|---|
| Znacznik czasu | Tak — 48-bitowy uniksowy ms | Nie |
| Sortowalny | Tak | Nie |
| Domyślna długość | 26 znaków | 21 znaków |
| Entropia | 80 bitów (komponent losowy) | ~126 bitów |
| Alfabet | Crockford Base32 (32 znaki) | URL-safe Base64 (64 znaki) |
| Konfigurowalna długość | Nie | Tak (dowolna długość) |
| Przypadek użycia | Posortowane według czasu identyfikatory, klucze główne bazy danych | Losowe tokeny, krótkie URL-e, klucze API |
Wybierz ULID, gdy potrzebujesz porządku czasowego. Wybierz nanoid, gdy potrzebujesz maksymalnej entropii w krótkim, losowym ciągu.
Używanie ULID w bazach danych
ULID-y można przechowywać w bazach danych na kilka sposobów w zależności od wymagań:
Przykłady kodu
Generowanie ULID wymaga biblioteki ulid (dostępnej dla JavaScript, Python, Go, Rust i innych):
// Using the 'ulid' npm package
import { ulid } from 'ulid'
const id = ulid() // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
const id2 = ulid() // "01ARZ3NDEKXXXXXXXXXXXX..." (same ms, incremented random)
// With a custom timestamp
const id3 = ulid(1469918176385) // deterministic time portion
// Extract the timestamp back out
import { decodeTime } from 'ulid'
decodeTime(id) // → 1469918176385 (Unix ms)# Using python-ulid
from ulid import ULID
uid = ULID()
str(uid) # "01ARZ3NDEKTSV4RRFFQ69G5FAV"
uid.timestamp # 1469918176.385
uid.datetime # datetime(2016, 7, 30, 23, 36, 16, 385000, tzinfo=timezone.utc)
# Parse an existing ULID string
parsed = ULID.from_str("01ARZ3NDEKTSV4RRFFQ69G5FAV")
parsed.timestamp # 1469918176.385-- Store ULIDs as TEXT or CHAR(26)
CREATE TABLE events (
id CHAR(26) PRIMARY KEY DEFAULT gen_ulid(), -- if using a PG extension
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Or pass the ULID from your application layer
INSERT INTO events (id, name, created_at)
VALUES ('01ARZ3NDEKTSV4RRFFQ69G5FAV', 'user.signup', NOW());
-- Range queries are efficient because ULIDs sort chronologically
SELECT * FROM events
WHERE id > '01ARZ3NDEKTSV4RRFFQ69G5FAV'
ORDER BY id
LIMIT 20;// Pure browser / Deno / Node.js implementation (no dependencies)
const CROCKFORD = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'
function encodeTime(ms) {
let result = '', n = BigInt(ms)
for (let i = 9; i >= 0; i--) {
result = CROCKFORD[Number(n & 31n)] + result
n >>= 5n
}
return result
}
function encodeRandom(bytes) {
let n = 0n
for (const b of bytes) n = (n << 8n) | BigInt(b)
let result = ''
for (let i = 15; i >= 0; i--) {
result = CROCKFORD[Number(n & 31n)] + result
n >>= 5n
}
return result
}
function generateULID() {
const randomBytes = new Uint8Array(10)
crypto.getRandomValues(randomBytes)
return encodeTime(Date.now()) + encodeRandom(randomBytes)
}