ULID-generator – unikke, tidsorterbare ID'er uden bindestreger
ULID (Universally Unique Lexicographically Sortable Identifier) er et 128-bit identifikationsformat, der producerer 26-tegns strenge uden bindestreger. Hvor UUID v4 kræver 36 tegn og kun kan sorteres tilfældigt, giver ULID dig en kortere, case‑insensitiv streng, der er lexikografisk sorterbar efter oprettelsestidspunktet. På denne side vælger du blot formatet ULID, angiver et antal mellem 1 og 100, og generatoren udskriver straks en liste af færdige ID'er. Tilstødende toggles for store bogstaver eller bindestreger findes ikke – ULID er per definition case‑insensitiv og hyphene er fraværende.
Hvad gør ULID anderledes end UUID?
ULID's styrke ligger i kombinationen af længde, sorterbarhed og tegnsæt. En UUID v4 er 36 tegn (32 hexadecimale cifre plus fire bindestreger) og er rent tilfældig. En ULID er 26 tegn, bruger Crockfords base32-alfabet og indlejrer et millisekundpræcist tidsstempel i de første 10 tegn. Det betyder, at ULID'er sorteres i kronologisk rækkefølge uden et separat tidsstempel i databasen.
Crockfords base32-alfabet (0-9, A-Z minus I, L, O, U) er designet til at undgå visuel forveksling. Bogstaver som I og 1 eller O og 0 er udeladt, og store og små bogstaver behandles ens. Det gør ULID'er lettere at afskrive manuelt og mindre fejlbehæftede end hexadecimale UUID'er, hvor f.eks. b og 6 kan forveksles. Samtidig er alle ULID-tegn URL-sikre ifølge RFC 3986 – der kræves ingen procentkodning.
En anden forskel: på denne side kan du ikke skifte mellem store og små bogstaver eller tilføje bindestreger. ULID har simpelthen ikke disse muligheder, fordi formatet er defineret uden dem.
Sådan er en ULID opbygget
De 128 bit i en ULID fordeles på to komponenter:
| Komponent | Bit | Tegn (base32) | Beskrivelse |
|---|---|---|---|
| Tidsstempel | 48 bit | 10 tegn | Millisekunder siden Unix epoch (1970-01-01) |
| Tilfældig del | 80 bit | 16 tegn | Kryptografisk stærk tilfældighed |
De 48 bit giver plads til omkring 8,9 millioner år, før tidsstemplet løber over. Det er rigeligt til alle praktiske anvendelser. De 80 bit tilfældighed giver 2^80 ≈ 1,2 × 10^24 mulige værdier pr. millisekund, hvilket gør kollisioner ekstremt usandsynlige selv ved høj generationstakt.
Tidsstemplet konverteres til Crockford base32, og det samme gøres med den tilfældige del. Resultatet sættes sammen til en streng som f.eks. 01ARZ3NDEKTSV4RRFFQ69G5FAV. De første 10 tegn (01ARZ3NDEK) repræsenterer tidsstemplet, de sidste 16 (TSV4RRFFQ69G5FAV) den tilfældige del.
Fordi tidsstemplet udgør de første 10 tegn, vil en ULID, der er oprettet ét millisekund senere, altid være leksikografisk større end en tidligere ULID – forudsat at de to tidsstempler er forskellige. Hvis to ULID'er oprettes inden for samme millisekund, er den indbyrdes sortering ikke garanteret; deres rækkefølge bestemmes da af den tilfældige del.
Crockford Base32 – alfabetet der gør ULID robust
Crockford base32 er et 32-tegns alfabet, der blev defineret af Douglas Crockford til at være mere menneskelæsbart end almindelig hex eller base64. Alfabetet består af:
0123456789ABCDEFGHJKMNPQRSTVWXYZ
Bogstaverne I, L, O og U er udeladt. I kan forveksles med 1, L med 1, O med 0, og U med V i nogle skrifttyper. Ved at fjerne dem fjernes en væsentlig kilde til læsefejl.
Alfabetet er case‑insensitivt. a og A læses som samme tegn, b og B som samme, osv. Det betyder, at du kan kopiere en ULID som 01arz3ndektsv4rrffq69g5fav, og den vil blive opfattet som identisk med 01ARZ3NDEKTSV4RRFFQ69G5FAV. Hverken database eller applikation skal håndtere blanding af store og små bogstaver.
Sammen med den korte længde på 26 tegn gør dette ULID til et praktisk valg, når identifikatorer skal afskrives, læses højt over telefon eller indtastes manuelt.
ULID i praksis: sortering, kollisioner og ydeevne
Sorteringsadfærd
ULID er designet til at være lexikografisk sorterbart. Hvis du opretter en liste af ULID'er og sorterer den alfanumerisk, vil rækkefølgen svare til oprettelsestidspunktet – med en undtagelse: ULID'er fra samme millisekund kan komme i vilkårlig rækkefølge, fordi den tilfældige del afgør deres indbyrdes placering. Det er ikke en fejl, men en bevidst afvejning mellem sorterbarhed og kryptografisk entropi.
I praksis betyder det, at ULID'er er velegnede som primærnøgler i B‑træ‑indekserede databaser (f.eks. PostgreSQL, MySQL, SQLite). Da nye nøgler ofte har højere tidsstempler, indsættes de typisk i slutningen af indekset, hvilket reducerer behovet for sidenedsplittelse og genbalancering. Randomiserede UUID'er spreder derimod indsættelser over hele indeksområdet, hvilket øger skriveomkostningerne.
Kollisionssandsynlighed
Den tilfældige del på 80 bit giver 2^80 mulige værdier. Selv hvis du genererer 1 million ULID'er pr. millisekund (1 mia. i sekundet), er sandsynligheden for en kollision i samme millisekund omkring 2^-50 ≈ 10^-15. For langt de fleste anvendelser er risikoen negligeabel.
ULID bruger crypto.getRandomValues() til at generere den tilfældige del. Det er browserens indbyggede kryptografisk stærke tilfældighedsgenerator, som trækker på systemets entropikilde (f.eks. /dev/urandom på Linux). ID'erne skabes udelukkende lokalt i din browser – ingen data sendes til nogen server.
Hvordan ULID-generatoren på denne side fungerer
Grænsefladen er enkel: du vælger ULID fra formatlisten, indtaster et tal mellem 1 og 100 i antalsfeltet, og klikker på genereringsknappen. Hver gang du ændrer format, antal eller en anden indstilling, genskabes listen helt fra bunden.
Hvert ID vises som en 26‑tegns streng, der er klar til at blive kopieret. Klik på et enkelt ID for at kopiere det til udklipsholderen; klik på "Kopier alle" for at kopiere hele listen på én gang. Statuslinjen viser beskeden "Klar." eller "Genereret." og skifter til "Kopieret alle!" når hele listen er kopieret. Der er ingen mulighed for at vælge store eller små bogstaver eller tilføje bindestreger, fordi formatet ikke understøtter det.
Generatoren håndterer kun antal mellem 1 og 100. Værdier uden for dette interval accepteres ikke. Alle ID'er genereres med det samme i browseren – du skal ikke vente på netværksanmodninger, og dine data forlader aldrig din computer.
FAQ
Hvorfor er ULID kortere end UUID?
ULID bruger Crockford base32 (32 tegn pr. position) i stedet for hex (16 tegn pr. position). For at repræsentere 128 bit kræver hex 32 tegn plus 4 bindestreger = 36 tegn. Base32 kræver kun 26 tegn (128 / 5 = 25,6 → 26 tegn). Ingen bindestreger sparer yderligere plads.
Kan to ULID'er genereret samtidig være ens?
Kollisioner er ekstremt usandsynlige. Med 80 bit tilfældig del er der 1.208.925.819.614.629.174.706.176 muligheder pr. millisekund. Sandsynligheden for en kollision stiger med antallet af genererede ID'er, men for op til 100 tusind ID'er pr. millisekund er den under 4 × 10^-9.
Er ULID altid sorterbart?
Ja, med en præcisering: ULID'er sorteres korrekt efter tidsstempel, men ID'er oprettet inden for samme millisekund kan have vilkårlig indbyrdes rækkeføjle, fordi den tilfældige del afgør sorteringen. Hvis du har brug for streng kronologisk orden ned til nanosekundet, er ULID ikke det rigtige valg.
Kan jeg bruge ULID som primærnøgle i en relationel database?
Ja, og det er en af ULID's primære anvendelser. Tidssorterbarheden giver bedre B‑træ‑ydeevne end tilfældige UUID'er, fordi nye rækker ofte indsættes i slutningen af indekset. Du skal blot være opmærksom på, at ULID er 26 tegn (tekst), så kolonnen skal være af en teksttype (f.eks. VARCHAR(26)).
Hvorfor har generatoren ingen indstilling for store/små bogstaver?
Fordi ULID er case‑insensitivt. Crockford base32 behandler store og små bogstaver som identiske. En toggle ville være meningsløs – samme ULID i store og små bogstaver er to repræsentationer af samme værdi.
Bliver mine ULID'er sendt til en server?
Nej. Al generering sker lokalt i din browser ved hjælp af crypto.getRandomValues(). Når du trykker på genereringsknappen, udregnes ID'erne på din egen maskine, og resultatet vises kun for dig. Ingen data forlader dit system.