Générateur ULID

Génère des identifiants uniques triables lexicographiquement

Quantité

Cliquez sur Générer pour créer des ULIDs

Qu'est-ce qu'un ULID ?

ULID (Universally Unique Lexicographically Sortable Identifier) est un format d'identifiant de 128 bits conçu pour être à la fois unique et naturellement triable. Contrairement à UUID v4, qui est entièrement aléatoire, un ULID intègre un horodatage Unix de précision milliseconde dans ses bits de poids fort — garantissant que les identifiants générés plus tard se trient après les identifiants générés plus tôt.

Les ULID sont encodés en utilisant l'alphabet Crockford Base32, produisant une chaîne compacte de 26 caractères qui est URL-safe, insensible à la casse et exempte de caractères visuellement ambigus.

La spécification ULID a été créée par Alizain Feerasta et est largement utilisée dans les systèmes distribués, l'event sourcing et les clés primaires de base de données où l'unicité et l'ordre chronologique comptent tous deux. Les ULID ne sont pas une norme IETF — ce sont une spécification communautaire disponible sur ulid.github.io.

Structure ULID

Un ULID fait 128 bits de large, divisé en deux composants :

HorodatageAléatoire
01ARZ3NDEKTSVE4RRFFQ69G5FAV
48 bits — horodatage Unix en millisecondes. Encode le temps de génération avec une précision de 1 ms. Couvre les dates jusqu'à l'an 10889.80 bits — données aléatoires cryptographiquement sécurisées. Régénérées pour chaque ULID (sauf si le mode monotone est utilisé).

Encodé comme 26 caractères Crockford Base32 : les 10 premiers caractères représentent l'horodatage, les 16 derniers représentent le composant aléatoire.

Alphabet Crockford Base32

Les ULID utilisent l'encodage Crockford Base32, qui utilise 32 des 36 caractères alphanumériques. L'alphabet est : 0123456789ABCDEFGHJKMNPQRSTVWXYZ

Pourquoi ces 32 caractères ?
0123456789ABCDEFGHJKMNPQRSTVWXYZ

Quatre caractères sont intentionnellement exclus :

  • I et L sont exclus — facilement confondus avec le chiffre 1
  • O est exclu — facilement confondu avec le chiffre 0
  • U est exclu — évite les mots obscènes accidentels dans les identifiants générés
  • L'encodage est insensible à la casse01ARZ3NDEKTSV4RRFFQ69G5FAV et 01arz3ndektsv4rrffq69g5fav sont le même ULID

Crockford Base32 est plus efficace que l'hexadécimal (32 symboles vs 16) et plus lisible par l'humain que Base64 (pas de caractères + / =, insensible à la casse).

ULID vs UUID

Les ULID et les UUID représentent tous deux des identifiants de 128 bits, mais diffèrent significativement dans l'encodage et les objectifs de conception :

PropriétéULIDUUID
FormatCrockford Base32Hexadécimal avec tirets
Longueur26 caractères36 caractères
HorodatageUnix ms de 48 bitsAucun (v4) ou ms de 48 bits (v7)
TriableOui — lexicographiqueNon (v4) / Oui (v7)
URL-safeOui (alphanumérique uniquement)Oui (avec tirets)
DépendancesNécessite une bibliothèqueNatif (crypto.randomUUID)
Support BDStocker comme CHAR(26) ou BINARY(16)Type de colonne UUID natif
SpecSpec communautaire (ulid.github.io)RFC 4122 / RFC 9562

Si vous êtes déjà dans un écosystème UUID (colonnes uuid PostgreSQL, API REST, ORM avec support UUID), UUID v7 est généralement plus adapté que ULID. Si vous préférez un encodage plus convivial et contrôlez toute la pile, ULID est un excellent choix.

ULID vs nanoid

ULID et nanoid produisent tous deux des identifiants courts et URL-safe, mais ont des objectifs de conception différents :

PropriétéULIDNanoID
HorodatageOui — Unix ms de 48 bitsNon
TriableOuiNon
Longueur par défaut26 caractères21 caractères
Entropie80 bits (composant aléatoire)~126 bits
AlphabetCrockford Base32 (32 chars)URL-safe Base64 (64 chars)
Longueur personnalisableNonOui (n'importe quelle longueur)
Cas d'usageIdentifiants ordonnés dans le temps, clés primaires BDJetons aléatoires, URL courtes, clés API

Choisissez ULID quand vous avez besoin d'un ordre chronologique. Choisissez nanoid quand vous avez besoin d'une entropie maximale dans une chaîne courte et aléatoire.

Utiliser les ULID dans les bases de données

Les ULID peuvent être stockés dans les bases de données de plusieurs façons selon vos exigences :

Stocker comme CHAR(26)
L'approche la plus simple. L'ordre de tri lexicographique est préservé. Légèrement plus grand que le stockage binaire mais lisible par l'humain et facile à déboguer.
Stocker comme BINARY(16)
Décoder le ULID en sa représentation binaire de 16 octets pour un stockage compact. Nécessite un encodage/décodage dans le code applicatif. L'ordre de tri est préservé.
PostgreSQL
Stocker comme CHAR(26) ou utiliser le type bytea pour le stockage binaire. Il n'y a pas de type ULID natif, mais le tri lexicographique sur CHAR(26) fonctionne correctement.
MySQL / MariaDB
Utiliser CHAR(26) CHARACTER SET ascii pour un stockage efficace. Le stockage binaire dans BINARY(16) fonctionne également et économise de l'espace.
SQLite
Stocker comme TEXT. La comparaison de texte par défaut de SQLite trie les ULID correctement grâce à leur conception lexicographique.
MongoDB
Stocker comme champ chaîne. La triabilité lexicographique de ULID fonctionne naturellement avec la comparaison de chaînes de MongoDB.

Exemples de code

La génération ULID nécessite la bibliothèque ulid (disponible pour JavaScript, Python, Go, Rust et plus) :

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

Foire Aux Questions

Les ULID sont-ils globalement uniques ?
Oui — avec une très haute probabilité. Le composant aléatoire de 80 bits fournit 2^80 ≈ 1,2 × 10^24 valeurs possibles par milliseconde par générateur. La probabilité d'une collision dans la même milliseconde à travers différents générateurs est négligeable pour tout système pratique. Pour des garanties d'unicité strictes, utilisez le mode monotone, qui incrémente le composant aléatoire pour les identifiants générés dans la même milliseconde.
Un ULID est-il identique à un UUID ?
Non — les ULID et les UUID sont des encodages différents d'une valeur de 128 bits. Un ULID ne peut pas être directement substitué à un UUID dans des systèmes qui valident le format UUID (hexadécimal avec tirets). Cependant, vous pouvez convertir entre les représentations binaires ULID et UUID si nécessaire.
Comment fonctionne le mode monotone ULID ?
En mode standard, le composant aléatoire de 80 bits est fraîchement généré pour chaque ULID. En mode monotone, quand plusieurs ULID sont générés dans la même milliseconde, le composant aléatoire du deuxième et des identifiants suivants est la valeur aléatoire précédente plus un. Cela garantit un ordre monotone strict dans une milliseconde sur un seul générateur.
Puis-je décoder un ULID pour obtenir l'horodatage de génération ?
Oui. Les 10 premiers caractères Crockford Base32 encodent l'horodatage Unix de 48 bits en millisecondes. Décodez ces caractères en utilisant l'alphabet Crockford Base32, interprétez le résultat comme un horodatage Unix en millisecondes et convertissez en date. Cet outil fait exactement cela.
ULID est-il une norme officielle ?
Non. ULID est une spécification communautaire maintenue sur ulid.github.io. Ce n'est pas une norme IETF comme UUID. Cela signifie qu'il n'y a pas de RFC officiel à référencer, et les implémentations peuvent varier légèrement. UUID v7 (RFC 9562, 2024) est l'alternative standardisée par l'IETF avec des propriétés d'ordre chronologique similaires.