ULID Generator

Generate lexicographically sortable unique IDs

Počet

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ítkoNáhodné
01ARZ3NDEKTSVE4RRFFQ69G5FAV
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

Proč těchto 32 znaků?
0123456789ABCDEFGHJKMNPQRSTVWXYZ

Čtyři znaky jsou záměrně vyloučeny:

  • I a L jsou vyloučeny — snadno zaměnitelné s číslicí 1
  • O je vyloučeno — snadno zaměnitelné s číslicí 0
  • U je 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ísmen01ARZ3NDEKTSV4RRFFQ69G5FAV a 01arz3ndektsv4rrffq69g5fav jsou 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:

VlastnostULIDUUID
FormátCrockford Base32Hexadecimální s pomlčkami
Délka26 znaků36 znaků
Časové razítko48bitový 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ávislostiVyžaduje knihovnuNativní (crypto.randomUUID)
Podpora DBUložit jako CHAR(26) nebo BINARY(16)Nativní typ sloupce UUID
SpecKomunitní 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:

VlastnostULIDNanoID
Časové razítkoAno — 48bitový Unix msNe
SeřaditelnéAnoNe
Výchozí délka26 znaků21 znaků
Entropi e80 bitů (náhodná komponenta)~126 bitů
AbecedaCrockford Base32 (32 znaků)URL-bezpečný Base64 (64 znaků)
Přizpůsobitelná délkaNeAno (libovolná délka)
Případ použitíČasově uspořádaná ID, DB primární klíčeNá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:

Uložit jako CHAR(26)
Nejjednodušší přístup. Lexikografické pořadí třídění je zachováno. Mírně větší než binární úložiště, ale čitelné pro člověka a snadno laditelné.
Uložit jako BINARY(16)
Dekódujte ULID do jeho 16bajtové binární reprezentace pro kompaktní úložiště. Vyžaduje kódování/dekódování v kódu aplikace. Pořadí třídění je zachováno.
PostgreSQL
Uložte jako CHAR(26) nebo použijte typ bytea pro binární úložiště. Neexistuje nativní typ ULID, ale lexikografické uspořádání na CHAR(26) funguje správně.
MySQL / MariaDB
Použijte CHAR(26) CHARACTER SET ascii pro efektivní úložiště. Binární úložiště v BINARY(16) také funguje a šetří místo.
SQLite
Uložte jako TEXT. Výchozí porovnání textu SQLite třídí ULID správně díky jejich lexikografickému návrhu.
MongoDB
Uložte jako pole řetězce. Lexikografická seřaditelnost ULID funguje přirozeně s porovnáváním řetězců MongoDB.

Příklady kódu

Generování ULID vyžaduje knihovnu ulid (dostupná pro JavaScript, Python, Go, Rust a další):

JavaScript (ulid npm)
// 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)
Python (python-ulid)
# 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
PostgreSQL
-- 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;
JavaScript (pure — no dependencies)
// 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)
}

Časté dotazy

Jsou ULID globálně jedinečné?
Ano — s velmi vysokou pravděpodobností. 80bitová náhodná komponenta poskytuje 2^80 ≈ 1,2 × 10^24 možných hodnot za milisekundu na generátor. Pravděpodobnost kolize ve stejné milisekundě napříč různými generátory je pro jakýkoliv praktický systém zanedbatelná. Pro přísné záruky jedinečnosti použijte monotonický režim, který inkrementuje náhodnou komponentu pro ID generovaná ve stejné milisekundě.
Je ULID totéž jako UUID?
Ne — ULID a UUID jsou různá kódování 128bitové hodnoty. ULID nemůže být přímo nahrazeno za UUID v systémech, které validují formát UUID (hexadecimální s pomlčkami). Pokud je to potřeba, můžete však konvertovat mezi binárními reprezentacemi ULID a UUID.
Jak funguje monotonický režim ULID?
Ve standardním režimu je 80bitová náhodná komponenta pro každý ULID znovu vygenerována. V monotonickém režimu, když je více ULID generováno ve stejné milisekundě, je náhodná komponenta druhého a následujících ID předchozí náhodná hodnota plus jedna. To zajišťuje přísné monotonické uspořádání v rámci milisekundy na jednom generátoru.
Mohu dekódovat ULID pro získání časového razítka generování?
Ano. Prvních 10 znaků Crockford Base32 kóduje 48bitové Unix millisekudové časové razítko. Dekódujte tyto znaky pomocí abecedy Crockford Base32, interpretujte výsledek jako Unix časové razítko v milisekundách a převeďte na datum. Tento nástroj to dělá přesně.
Je ULID oficiálním standardem?
Ne. ULID je komunitní specifikace udržovaná na ulid.github.io. Není to standard IETF jako UUID. To znamená, že neexistuje žádný oficiální RFC, na který by bylo možné odkazovat, a implementace se mohou mírně lišit. UUID v7 (RFC 9562, 2024) je alternativou standardizovanou IETF s podobnými vlastnostmi časového uspořádání.