ULID Generator
Generate lexicographically sortable unique IDs
Klikněte na Generovat pro vytvoření ULID
Co je ULID?
ULID (Universally Unique Lexicographically Sortable Identifier) je 128bitový formát identifikátoru navržený tak, aby byl jak jedinečný, tak přirozeně seřaditelný. Na rozdíl od UUID v4, který je zcela náhodný, ULID vkládá Unix časové razítko s přesností na milisekundy do svých vysokých bitů — zajišťující, že ID generovaná později se třídí za ID generovanými dříve.
ULID jsou kódovány pomocí abecedy Crockford Base32, čímž vzniká kompaktní 26znakový řetězec, který je URL-bezpečný, nerozlišuje velikost písmen a neobsahuje vizuálně nejednoznačné znaky.
Specifikaci ULID vytvořil Alizain Feerasta a je široce používána v distribuovaných systémech, event sourcingu a primárních klíčích databáze, kde záleží jak na jedinečnosti, tak na časovém uspořádání. ULID nejsou standardem IETF — jsou to komunitní specifikace dostupné na ulid.github.io.
Struktura ULID
ULID je 128 bitů wide, rozděleno do dvou komponent:
| Časové razítko | Náhodné |
|---|---|
| 01ARZ3NDEK | TSVE4RRFFQ69G5FAV |
| 48 bitů — Unix časové razítko v milisekundách. Kóduje čas generování s přesností 1ms. Pokrývá data do roku 10889. | 80 bitů — kryptograficky bezpečná náhodná data. Pro každý ULID znovu vygenerovaná (pokud není použit monotonický režim). |
Kódováno jako 26 znaků Crockford Base32: prvních 10 znaků představuje časové razítko, posledních 16 znaků představuje náhodnou komponentu.
Abeceda Crockford Base32
ULID používají kódování Crockford Base32, které používá 32 ze 36 alfanumerických znaků. Abeceda je: 0123456789ABCDEFGHJKMNPQRSTVWXYZ
Čtyři znaky jsou záměrně vyloučeny:
IaLjsou vyloučeny — snadno zaměnitelné s číslicí1Oje vyloučeno — snadno zaměnitelné s číslicí0Uje vyloučeno — vyhýbá se náhodným obscénním slovům v generovaných ID- Kódování je
nerozlišující velikost písmen—01ARZ3NDEKTSV4RRFFQ69G5FAVa01arz3ndektsv4rrffq69g5favjsou stejné ULID
Crockford Base32 je efektivnější než hexadecimální (32 symbolů vs 16) a čitelnější pro člověka než Base64 (žádné znaky + / =, nerozlišující velikost písmen).
ULID vs UUID
ULID i UUID představují 128bitové identifikátory, ale výrazně se liší v kódování a designových cílech:
| Vlastnost | ULID | UUID |
|---|---|---|
| Formát | Crockford Base32 | Hexadecimální s pomlčkami |
| Délka | 26 znaků | 36 znaků |
| Časové razítko | 48bitový Unix ms | Žádné (v4) nebo 48bitový ms (v7) |
| Seřaditelné | Ano — lexikografické | Ne (v4) / Ano (v7) |
| URL-bezpečné | Ano (pouze alfanumerické) | Ano (s pomlčkami) |
| Závislosti | Vyžaduje knihovnu | Nativní (crypto.randomUUID) |
| Podpora DB | Uložit jako CHAR(26) nebo BINARY(16) | Nativní typ sloupce UUID |
| Spec | Komunitní spec (ulid.github.io) | RFC 4122 / RFC 9562 |
Pokud jste již v ekosystému UUID (sloupce uuid v PostgreSQL, REST API, ORM s podporou UUID), UUID v7 je obvykle lepší volbou než ULID. Pokud preferujete přívětivější kódování pro člověka a ovládáte celý stack, ULID je vynikající volba.
ULID vs nanoid
Jak ULID, tak nanoid produkují krátké, URL-bezpečné identifikátory, ale mají různé designové cíle:
| Vlastnost | ULID | NanoID |
|---|---|---|
| Časové razítko | Ano — 48bitový Unix ms | Ne |
| Seřaditelné | Ano | Ne |
| Výchozí délka | 26 znaků | 21 znaků |
| Entropi e | 80 bitů (náhodná komponenta) | ~126 bitů |
| Abeceda | Crockford Base32 (32 znaků) | URL-bezpečný Base64 (64 znaků) |
| Přizpůsobitelná délka | Ne | Ano (libovolná délka) |
| Případ použití | Časově uspořádaná ID, DB primární klíče | Náhodné tokeny, krátké URL, API klíče |
Zvolte ULID, když potřebujete časové uspořádání. Zvolte nanoid, když potřebujete maximální entropii v krátkém, náhodném řetězci.
Používání ULID v databázích
ULID lze ukládat v databázích několika způsoby v závislosti na vašich požadavcích:
Příklady kódu
Generování ULID vyžaduje knihovnu ulid (dostupná pro JavaScript, Python, Go, Rust a další):
// 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)
}