ULID Generator
Generate lexicographically sortable unique IDs
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:
| Zeitstempel | Zufällig |
|---|---|
| 01ARZ3NDEK | TSVE4RRFFQ69G5FAV |
| 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
Vier Zeichen werden absichtlich ausgeschlossen:
IundLwerden ausgeschlossen — leicht mit der Ziffer1verwechseltOwird ausgeschlossen — leicht mit der Ziffer0verwechseltUwird ausgeschlossen — vermeidet versehentlich anstößige Wörter in generierten IDs- Die Kodierung ist
groß-/kleinschreibung-unabhängig—01ARZ3NDEKTSV4RRFFQ69G5FAVund01arz3ndektsv4rrffq69g5favsind 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:
| Eigenschaft | ULID | UUID |
|---|---|---|
| Format | Crockford-Base32 | Bindestriche-Hex |
| Länge | 26 Zeichen | 36 Zeichen |
| Zeitstempel | 48-Bit-Unix-ms | Keiner (v4) oder 48-Bit-ms (v7) |
| Sortierbar | Ja — lexikografisch | Nein (v4) / Ja (v7) |
| URL-sicher | Ja (nur alphanumerisch) | Ja (mit Bindestrichen) |
| Abhängigkeiten | Bibliothek erforderlich | Nativ (crypto.randomUUID) |
| DB-Unterstützung | Als CHAR(26) oder BINARY(16) speichern | Nativer UUID-Spaltentyp |
| Spezifikation | Community-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:
| Eigenschaft | ULID | NanoID |
|---|---|---|
| Zeitstempel | Ja — 48-Bit-Unix-ms | Nein |
| Sortierbar | Ja | Nein |
| Standardlänge | 26 Zeichen | 21 Zeichen |
| Entropie | 80 Bits (Zufallskomponente) | ~126 Bits |
| Alphabet | Crockford-Base32 (32 Zeichen) | URL-sicheres Base64 (64 Zeichen) |
| Anpassbare Länge | Nein | Ja (beliebige Länge) |
| Anwendungsfall | Zeitgeordnete IDs, DB-Primärschlüssel | Zufalls-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:
Code-Beispiele
ULID-Generierung erfordert die ulid-Bibliothek (für JavaScript, Python, Go, Rust und mehr verfügbar):
// 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)
}