ULID Generator

Generate lexicographically sortable unique IDs

Aantal

Klik op Genereren om ULIDs te maken

Wat is een ULID?

ULID (Universally Unique Lexicographically Sortable Identifier) is een 128-bit identificatorformaat ontworpen om zowel uniek als van nature sorteerbaar te zijn. In tegenstelling tot UUID v4, dat volledig willekeurig is, bevat een ULID een millisecondeprecisie Unix-tijdstempel in zijn hoge bits — wat ervoor zorgt dat later gegenereerde ID's sorteren na eerder gegenereerde ID's.

ULIDs worden gecodeerd met het Crockford Base32-alfabet, waarbij een compact 26-teken string wordt geproduceerd dat URL-veilig, hoofdletterongevoelig en vrij van visueel dubbelzinnige tekens is.

De ULID-specificatie werd gemaakt door Alizain Feerasta en wordt veel gebruikt in gedistribueerde systemen, event sourcing en database primaire sleutels waar zowel uniciteit als tijdvolgorde van belang zijn. ULIDs zijn geen IETF-standaard — ze zijn een community-specificatie beschikbaar op ulid.github.io.

ULID-structuur

Een ULID is 128 bits breed, verdeeld in twee componenten:

TijdstempelWillekeurig
01ARZ3NDEKTSVE4RRFFQ69G5FAV
48 bits — Unix-tijdstempel in milliseconden. Codeert de generatietijd met 1ms precisie. Dekt datums tot het jaar 10889.80 bits — cryptografisch veilige willekeurige gegevens. Vers gegenereerd voor elke ULID (tenzij monotoniemodus wordt gebruikt).

Gecodeerd als 26 Crockford Base32-tekens: de eerste 10 tekens vertegenwoordigen het tijdstempel, de laatste 16 tekens vertegenwoordigen de willekeurige component.

Crockford Base32-alfabet

ULIDs gebruiken Crockfords Base32-codering, die 32 van de 36 alfanumerieke tekens gebruikt. Het alfabet is: 0123456789ABCDEFGHJKMNPQRSTVWXYZ

Waarom deze 32 tekens?
0123456789ABCDEFGHJKMNPQRSTVWXYZ

Vier tekens worden opzettelijk uitgesloten:

  • I en L worden uitgesloten — gemakkelijk te verwarren met het cijfer 1
  • O wordt uitgesloten — gemakkelijk te verwarren met het cijfer 0
  • U wordt uitgesloten — vermijdt accidenteel aanstootgevende woorden in gegenereerde ID's
  • De codering is hoofdletterongevoelig01ARZ3NDEKTSV4RRFFQ69G5FAV en 01arz3ndektsv4rrffq69g5fav zijn dezelfde ULID

Crockford Base32 is efficiënter dan hexadecimaal (32 symbolen vs 16) en meer mensleesbaar dan Base64 (geen + / = tekens, hoofdletterongevoelig).

ULID vs UUID

ULIDs en UUIDs vertegenwoordigen beide 128-bit identificatoren, maar verschillen aanzienlijk in codering en ontwerpdoelen:

EigenschapULIDUUID
FormaatCrockford Base32Koppeltekens-hexadecimaal
Lengte26 tekens36 tekens
Tijdstempel48-bit Unix msGeen (v4) of 48-bit ms (v7)
SorteerbaarJa — lexicografischNee (v4) / Ja (v7)
URL-veiligJa (alleen alfanumeriek)Ja (met koppeltekens)
AfhankelijkhedenBibliotheek vereistNative (crypto.randomUUID)
DB-ondersteuningOpslaan als CHAR(26) of BINARY(16)Native UUID-kolomtype
SpecificatieCommunity-specificatie (ulid.github.io)RFC 4122 / RFC 9562

Als u zich al in een UUID-ecosysteem bevindt (PostgreSQL uuid-kolommen, REST-API's, ORMs met UUID-ondersteuning), is UUID v7 gewoonlijk een betere keuze dan ULID. Als u vers begint en de voorkeur geeft aan een meer gebruikersvriendelijke codering en de volledige stack beheert, is ULID een uitstekende keuze.

ULID vs nanoid

Zowel ULID als nanoid produceren korte, URL-veilige identificatoren, maar ze hebben verschillende ontwerpdoelen:

EigenschapULIDNanoID
TijdstempelJa — 48-bit Unix msNee
SorteerbaarJaNee
Standaardlengte26 tekens21 tekens
Entropie80 bits (willekeurige component)~126 bits
AlfabetCrockford Base32 (32 tekens)URL-veilig Base64 (64 tekens)
Aanpasbare lengteNeeJa (elke lengte)
GebruiksscenarioTijdgeordende ID's, DB primaire sleutelsWillekeurige tokens, korte URL's, API-sleutels

Kies ULID wanneer u tijdvolgorde nodig heeft. Kies nanoid wanneer u maximale entropie in een korte, willekeurige string nodig heeft.

ULIDs in databases gebruiken

ULIDs kunnen op verschillende manieren worden opgeslagen in databases afhankelijk van uw vereisten:

Opslaan als CHAR(26)
De eenvoudigste aanpak. Lexicografische sorteervolgorde blijft behouden. Iets groter dan binaire opslag maar mensleesbaar en gemakkelijk te debuggen.
Opslaan als BINARY(16)
Decodeer de ULID naar zijn 16-byte binaire representatie voor compacte opslag. Vereist codering/decodering in applicatiecode. Sorteervolgorde blijft behouden.
PostgreSQL
Opslaan als CHAR(26) of gebruik het bytea-type voor binaire opslag. Er is geen native ULID-type, maar lexicografische ordening op CHAR(26) werkt correct.
MySQL / MariaDB
Gebruik CHAR(26) CHARACTER SET ascii voor efficiënte opslag. Binaire opslag in BINARY(16) werkt ook en bespaart ruimte.
SQLite
Opslaan als TEXT. SQLites standaard tekstvergelijking sorteert ULIDs correct vanwege hun lexicografisch ontwerp.
MongoDB
Opslaan als een stringveld. ULIDs lexicografische sorteerbaarheid werkt van nature met MongoDBs stringvergelijking.

Codevoorbeelden

ULID-generatie vereist de ulid-bibliotheek (beschikbaar voor JavaScript, Python, Go, Rust en meer):

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)
}

Veelgestelde vragen

Zijn ULIDs globaal uniek?
Ja — met zeer hoge waarschijnlijkheid. De 80-bit willekeurige component biedt 2^80 ≈ 1,2 × 10^24 mogelijke waarden per milliseconde per generator. De kans op een botsing binnen dezelfde milliseconde over verschillende generators is verwaarloosbaar voor elk praktisch systeem. Voor strikte uniciteitsgaranties gebruik monotoniemodus, die de willekeurige component verhoogt voor ID's gegenereerd binnen dezelfde milliseconde.
Is een ULID hetzelfde als een UUID?
Nee — ULIDs en UUIDs zijn verschillende coderingen van een 128-bit waarde. Een ULID kan niet direct worden vervangen door een UUID in systemen die het UUID-formaat (koppeltekens-hexadecimaal) valideren. U kunt echter converteren tussen binaire ULID- en UUID-representaties indien nodig.
Hoe werkt de ULID-monotoniemodus?
In standaardmodus wordt de 80-bit willekeurige component vers gegenereerd voor elke ULID. In monotoniemodus, wanneer meerdere ULIDs worden gegenereerd binnen dezelfde milliseconde, is de willekeurige component van de tweede en volgende ID's de vorige willekeurige waarde plus één. Dit zorgt voor strikte monotone ordening binnen een milliseconde op een enkele generator.
Kan ik een ULID decoderen om het generatietijdstempel te krijgen?
Ja. De eerste 10 Crockford Base32-tekens coderen het 48-bit Unix-millisecondentijdstempel. Decodeer die tekens met het Crockford Base32-alfabet, interpreteer het resultaat als een Unix-tijdstempel in milliseconden en converteer naar een datum. Dit hulpmiddel doet precies dat.
Is ULID een officiële standaard?
Nee. ULID is een community-specificatie bijgehouden op ulid.github.io. Het is geen IETF-standaard zoals UUID. Dit betekent dat er geen officiële RFC is waarnaar verwezen kan worden, en implementaties kunnen licht variëren. UUID v7 (RFC 9562, 2024) is het IETF-gestandaardiseerde alternatief met vergelijkbare tijdordeningseigenschappen.