ULID Generator

Generate lexicographically sortable unique IDs

Anzahl

Klicken Sie auf Generieren, um ULIDs zu erstellen

Was ist eine ULID?

ULID (Universally Unique Lexicographically Sortable Identifier) ist ein 128-Bit-Bezeichner-Format, das sowohl eindeutig als auch natürlich sortierbar sein soll. Im Gegensatz zu UUID v4, das vollständig zufällig ist, enthält ein ULID einen Millisekunden-präzisen Unix-Zeitstempel in seinen hohen Bits — was sicherstellt, dass später generierte IDs nach früher generierten sortieren.

ULIDs werden mit dem Crockford-Base32-Alphabet kodiert und erzeugen einen kompakten 26-Zeichen-String, der URL-sicher, groß-/kleinschreibung-unabhängig und frei von visuell mehrdeutigen Zeichen ist.

Die ULID-Spezifikation wurde von Alizain Feerasta erstellt und wird in verteilten Systemen, Event-Sourcing und Datenbankprimärschlüsseln weit verbreitet verwendet, wo sowohl Eindeutigkeit als auch Zeitreihenfolge wichtig sind. ULIDs sind kein IETF-Standard — sie sind eine Community-Spezifikation, verfügbar unter ulid.github.io.

ULID-Struktur

Eine ULID ist 128 Bits breit, aufgeteilt in zwei Komponenten:

ZeitstempelZufällig
01ARZ3NDEKTSVE4RRFFQ69G5FAV
48 Bits — Unix-Zeitstempel in Millisekunden. Kodiert die Generierungszeit mit 1ms-Präzision. Deckt Daten bis zum Jahr 10889 ab.80 Bits — kryptografisch sichere Zufallsdaten. Für jede ULID frisch neu generiert (es sei denn, der Monotonie-Modus wird verwendet).

Kodiert als 26 Crockford-Base32-Zeichen: die ersten 10 Zeichen repräsentieren den Zeitstempel, die letzten 16 Zeichen repräsentieren die Zufallskomponente.

Crockford-Base32-Alphabet

ULIDs verwenden Crockfords Base32-Kodierung, die 32 der 36 alphanumerischen Zeichen verwendet. Das Alphabet ist: 0123456789ABCDEFGHJKMNPQRSTVWXYZ

Warum diese 32 Zeichen?
0123456789ABCDEFGHJKMNPQRSTVWXYZ

Vier Zeichen werden absichtlich ausgeschlossen:

  • I und L werden ausgeschlossen — leicht mit der Ziffer 1 verwechselt
  • O wird ausgeschlossen — leicht mit der Ziffer 0 verwechselt
  • U wird ausgeschlossen — vermeidet versehentlich anstößige Wörter in generierten IDs
  • Die Kodierung ist groß-/kleinschreibung-unabhängig01ARZ3NDEKTSV4RRFFQ69G5FAV und 01arz3ndektsv4rrffq69g5fav sind dieselbe ULID

Crockford-Base32 ist effizienter als hexadezimal (32 Symbole vs. 16) und menschenlesbarer als Base64 (keine + / = Zeichen, groß-/kleinschreibung-unabhängig).

ULID vs UUID

ULIDs und UUIDs repräsentieren beide 128-Bit-Bezeichner, unterscheiden sich aber erheblich in Kodierung und Designzielen:

EigenschaftULIDUUID
FormatCrockford-Base32Bindestriche-Hex
Länge26 Zeichen36 Zeichen
Zeitstempel48-Bit-Unix-msKeiner (v4) oder 48-Bit-ms (v7)
SortierbarJa — lexikografischNein (v4) / Ja (v7)
URL-sicherJa (nur alphanumerisch)Ja (mit Bindestrichen)
AbhängigkeitenBibliothek erforderlichNativ (crypto.randomUUID)
DB-UnterstützungAls CHAR(26) oder BINARY(16) speichernNativer UUID-Spaltentyp
SpezifikationCommunity-Spezifikation (ulid.github.io)RFC 4122 / RFC 9562

Wenn Sie sich bereits in einem UUID-Ökosystem befinden (PostgreSQL-uuid-Spalten, REST-APIs, ORMs mit UUID-Unterstützung), ist UUID v7 normalerweise eine bessere Wahl als ULID. Wenn Sie von vorne beginnen und eine menschenfreundlichere Kodierung bevorzugen und den gesamten Stack kontrollieren, ist ULID eine ausgezeichnete Wahl.

ULID vs nanoid

Sowohl ULID als auch nanoid erzeugen kurze, URL-sichere Bezeichner, haben aber unterschiedliche Designziele:

EigenschaftULIDNanoID
ZeitstempelJa — 48-Bit-Unix-msNein
SortierbarJaNein
Standardlänge26 Zeichen21 Zeichen
Entropie80 Bits (Zufallskomponente)~126 Bits
AlphabetCrockford-Base32 (32 Zeichen)URL-sicheres Base64 (64 Zeichen)
Anpassbare LängeNeinJa (beliebige Länge)
AnwendungsfallZeitgeordnete IDs, DB-PrimärschlüsselZufalls-Token, Kurz-URLs, API-Schlüssel

Wählen Sie ULID, wenn Sie Zeitreihenfolge benötigen. Wählen Sie nanoid, wenn Sie maximale Entropie in einem kurzen, zufälligen String benötigen.

ULIDs in Datenbanken verwenden

ULIDs können je nach Anforderungen auf verschiedene Arten in Datenbanken gespeichert werden:

Als CHAR(26) speichern
Der einfachste Ansatz. Die lexikografische Sortierreihenfolge bleibt erhalten. Etwas größer als binäre Speicherung, aber menschenlesbar und leicht zu debuggen.
Als BINARY(16) speichern
Die ULID zur kompakten Speicherung in ihre 16-Byte-binäre Darstellung dekodieren. Erfordert Kodierung/Dekodierung im Anwendungscode. Die Sortierreihenfolge bleibt erhalten.
PostgreSQL
Als CHAR(26) speichern oder den bytea-Typ für binäre Speicherung verwenden. Es gibt keinen nativen ULID-Typ, aber die lexikografische Reihenfolge auf CHAR(26) funktioniert korrekt.
MySQL / MariaDB
CHAR(26) CHARACTER SET ascii für effiziente Speicherung verwenden. Binäre Speicherung in BINARY(16) funktioniert ebenfalls und spart Platz.
SQLite
Als TEXT speichern. SQLites Standard-Textvergleich sortiert ULIDs korrekt aufgrund ihres lexikografischen Designs.
MongoDB
Als String-Feld speichern. ULIDs lexikografische Sortierbarkeit funktioniert natürlich mit MongoDBs String-Vergleich.

Code-Beispiele

ULID-Generierung erfordert die ulid-Bibliothek (für JavaScript, Python, Go, Rust und mehr verfügbar):

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

Häufig gestellte Fragen

Sind ULIDs global eindeutig?
Ja — mit sehr hoher Wahrscheinlichkeit. Die 80-Bit-Zufallskomponente bietet 2^80 ≈ 1,2 × 10^24 mögliche Werte pro Millisekunde pro Generator. Die Wahrscheinlichkeit einer Kollision innerhalb derselben Millisekunde über verschiedene Generatoren hinweg ist für jedes praktische System vernachlässigbar. Für strikte Eindeutigkeitsgarantien verwenden Sie den Monotonie-Modus, der die Zufallskomponente für IDs, die innerhalb derselben Millisekunde generiert werden, erhöht.
Ist eine ULID dasselbe wie eine UUID?
Nein — ULIDs und UUIDs sind unterschiedliche Kodierungen eines 128-Bit-Werts. Eine ULID kann nicht direkt durch eine UUID in Systemen ersetzt werden, die das UUID-Format (Bindestriche-Hex) validieren. Sie können jedoch zwischen binären ULID- und UUID-Darstellungen konvertieren, wenn nötig.
Wie funktioniert der ULID-Monotonie-Modus?
Im Standardmodus wird die 80-Bit-Zufallskomponente für jede ULID frisch generiert. Im Monotonie-Modus wird bei mehreren ULIDs, die innerhalb derselben Millisekunde generiert werden, die Zufallskomponente der zweiten und folgenden IDs der vorherige Zufallswert plus eins. Das stellt eine streng monoton steigende Reihenfolge innerhalb einer Millisekunde auf einem einzelnen Generator sicher.
Kann ich eine ULID dekodieren, um den Generierungszeitstempel zu erhalten?
Ja. Die ersten 10 Crockford-Base32-Zeichen kodieren den 48-Bit-Unix-Millisekunden-Zeitstempel. Dekodieren Sie diese Zeichen mit dem Crockford-Base32-Alphabet, interpretieren Sie das Ergebnis als Unix-Zeitstempel in Millisekunden und konvertieren Sie es in ein Datum. Dieses Tool tut genau das.
Ist ULID ein offizieller Standard?
Nein. ULID ist eine Community-Spezifikation, die unter ulid.github.io gepflegt wird. Es ist kein IETF-Standard wie UUID. Das bedeutet, es gibt keinen offiziellen RFC als Referenz, und Implementierungen können leicht variieren. UUID v7 (RFC 9562, 2024) ist die IETF-standardisierte Alternative mit ähnlichen Zeitordnungseigenschaften.