ULID Generator

Generate lexicographically sortable unique IDs

Antal

Klicka på Generera för att skapa ULIDs

Vad är en ULID?

ULID (Universally Unique Lexicographically Sortable Identifier) är ett 128-bitars identifierarformat utformat för att vara både unikt och naturligt sorterbart. Till skillnad från UUID v4, som är helt slumpmässigt, bäddar en ULID in en millisekundprecisions Unix-tidsstämpel i sina höga bitar — vilket säkerställer att ID:n som genereras senare sorteras efter ID:n som genererats tidigare.

ULID:ar kodas med Crockfords Base32-alfabet, vilket ger en kompakt 26-teckens sträng som är URL-säker, skiftlägeskänslig och fri från visuellt tvetydiga tecken.

ULID-specifikationen skapades av Alizain Feerasta och används allmänt i distribuerade system, händelsekällor och databasprimärnycklar där både unicitet och tidsordning spelar roll. ULID:ar är inte en IETF-standard — de är en gemenskapsspecifikation tillgänglig på ulid.github.io.

ULID-struktur

En ULID är 128 bitar bred, uppdelad i två komponenter:

TidsstämpelSlumpmässig
01ARZ3NDEKTSVE4RRFFQ69G5FAV
48 bitar — Unix-tidsstämpel i millisekunder. Kodar genereringstiden med 1ms precision. Täcker datum till år 10889.80 bitar — kryptografiskt säkra slumpmässiga data. Regenereras fräscht för varje ULID (om inte monotonicitetsläge används).

Kodad som 26 Crockford Base32-tecken: de första 10 tecknen representerar tidsstämpeln, de sista 16 tecknen representerar den slumpmässiga komponenten.

Crockford Base32-alfabetet

ULID:ar använder Crockfords Base32-kodning, som använder 32 av de 36 alfanumeriska tecknen. Alfabetet är: 0123456789ABCDEFGHJKMNPQRSTVWXYZ

Varför dessa 32 tecken?
0123456789ABCDEFGHJKMNPQRSTVWXYZ

Fyra tecken utesluts avsiktligt:

  • I och L utesluts — lätt förväxlade med siffran 1
  • O utesluts — lätt förväxlad med siffran 0
  • U utesluts — undviker oavsiktliga obscena ord i genererade ID:n
  • Kodningen är skiftlägeskänslig01ARZ3NDEKTSV4RRFFQ69G5FAV och 01arz3ndektsv4rrffq69g5fav är samma ULID

Crockford Base32 är effektivare än hexadecimalt (32 symboler vs 16) och mer mänskligt läsbar än Base64 (inga + / = tecken, skiftlägeskänslig).

ULID vs UUID

ULID:ar och UUID:n representerar båda 128-bitarsidentifierare, men skiljer sig avsevärt i kodning och designmål:

EgenskapULIDUUID
FormatCrockford Base32Bindestreck-hex
Längd26 tecken36 tecken
Tidsstämpel48-bitars Unix msIngen (v4) eller 48-bitars ms (v7)
SorterbarJa — lexikografiskNej (v4) / Ja (v7)
URL-säkerJa (enbart alfanumerisk)Ja (med bindestreck)
BeroendenKräver bibliotekInbyggd (crypto.randomUUID)
DB-stödLagra som CHAR(26) eller BINARY(16)Inbyggd UUID-kolumntyp
SpecGemenskapsspecifikation (ulid.github.io)RFC 4122 / RFC 9562

Om du redan befinner dig i ett UUID-ekosystem (PostgreSQL uuid-kolumner, REST-API:er, ORM:ar med UUID-stöd) är UUID v7 vanligtvis ett bättre val än ULID. Om du föredrar en mer mänskligt vänlig kodning och kontrollerar hela stacken, är ULID ett utmärkt val.

ULID vs nanoid

Både ULID och nanoid producerar korta, URL-säkra identifierare, men de har olika designmål:

EgenskapULIDNanoID
TidsstämpelJa — 48-bitars Unix msNej
SorterbarJaNej
Standardlängd26 tecken21 tecken
Entropi80 bitar (slumpmässig komponent)~126 bitar
AlfabetCrockford Base32 (32 tecken)URL-säker Base64 (64 tecken)
Anpassningsbar längdNejJa (valfri längd)
AnvändningsfallTidsordnade ID:n, DB-primärnycklarSlumpmässiga tokens, korta URL:er, API-nycklar

Välj ULID när du behöver tidsordning. Välj nanoid när du behöver maximal entropi i en kort, slumpmässig sträng.

Använda ULID:ar i databaser

ULID:ar kan lagras i databaser på flera sätt beroende på dina krav:

Lagra som CHAR(26)
Det enklaste tillvägagångssättet. Lexikografisk sorteringsordning bevaras. Något större än binär lagring men mänskligt läsbar och enkel att felsöka.
Lagra som BINARY(16)
Avkoda ULID:t till dess 16-bytes binära representation för kompakt lagring. Kräver kodning/avkodning i applikationskod. Sorteringsordning bevaras.
PostgreSQL
Lagra som CHAR(26) eller använd bytea-typen för binär lagring. Det finns ingen inbyggd ULID-typ, men lexikografisk ordning på CHAR(26) fungerar korrekt.
MySQL / MariaDB
Använd CHAR(26) CHARACTER SET ascii för effektiv lagring. Binär lagring i BINARY(16) fungerar också och sparar utrymme.
SQLite
Lagra som TEXT. SQLite:s standardtextjämförelse sorterar ULID:ar korrekt tack vare deras lexikografiska design.
MongoDB
Lagra som ett strängfält. ULID:s lexikografiska sorterbarhet fungerar naturligt med MongoDB:s strängj ämförelse.

Kodexempel

ULID-generering kräver ulid-biblioteket (tillgängligt för JavaScript, Python, Go, Rust med mera):

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

Vanliga frågor

Är ULID:ar globalt unika?
Ja — med mycket hög sannolikhet. Den 80-bitars slumpmässiga komponenten ger 2^80 ≈ 1,2 × 10^24 möjliga värden per millisekund per generator. Sannolikheten för en kollision inom samma millisekund över olika generatorer är försumbar för alla praktiska system. För strikta unikitetsgarantier, använd monotonicitetsläge, som ökar den slumpmässiga komponenten för ID:n som genereras inom samma millisekund.
Är en ULID detsamma som ett UUID?
Nej — ULID:ar och UUID:n är olika kodningar av ett 128-bitarsvärde. En ULID kan inte direkt ersättas mot ett UUID i system som validerar UUID-format (bindestreck-hex). Du kan dock konvertera mellan binär ULID- och UUID-representation om det behövs.
Hur fungerar ULID:s monotonicitetsläge?
I standardläge genereras den 80-bitars slumpmässiga komponenten nytt för varje ULID. I monotonicitetsläge, när flera ULID:ar genereras inom samma millisekund, är den slumpmässiga komponenten för det andra och efterföljande ID:n det föregående slumpmässiga värdet plus ett. Det säkerställer strikt monoton ordning inom en millisekund på en enda generator.
Kan jag avkoda en ULID för att få genereringstidsstämpeln?
Ja. De första 10 Crockford Base32-tecknen kodar den 48-bitars Unix-millisekundtidsstämpeln. Avkoda dessa tecken med Crockford Base32-alfabetet, tolka resultatet som en Unix-tidsstämpel i millisekunder och konvertera till ett datum. Det här verktyget gör exakt det.
Är ULID en officiell standard?
Nej. ULID är en gemenskapsspecifikation underhållen på ulid.github.io. Det är inte en IETF-standard som UUID. Det innebär att det inte finns någon officiell RFC att referera till, och implementationer kan variera något. UUID v7 (RFC 9562, 2024) är det IETF-standardiserade alternativet med liknande tidsordningsegenskaper.