Generador ULID

Genera identificadores únicos ordenables lexicográficamente

Cantidad

Haz clic en Generar para crear ULIDs

¿Qué es un ULID?

ULID (Identificador Universalmente Único Lexicográficamente Ordenable) es un formato de identificador de 128 bits diseñado para ser tanto único como naturalmente ordenable. A diferencia de UUID v4, que es completamente aleatorio, un ULID incorpora una marca de tiempo Unix con precisión de milisegundos en sus bits más significativos — asegurando que los IDs generados más tarde se ordenen después de los generados antes.

Los ULIDs se codifican usando el alfabeto Crockford Base32, produciendo una cadena compacta de 26 caracteres que es segura para URL, insensible a mayúsculas y libre de caracteres visualmente ambiguos.

La especificación ULID fue creada por Alizain Feerasta y es ampliamente utilizada en sistemas distribuidos, event sourcing y claves primarias de bases de datos donde importan tanto la unicidad como el ordenamiento temporal. Los ULIDs no son un estándar IETF — son una especificación comunitaria disponible en ulid.github.io.

Estructura ULID

Un ULID tiene 128 bits de ancho, dividido en dos componentes:

Marca de TiempoAleatorio
01ARZ3NDEKTSVE4RRFFQ69G5FAV
48 bits — marca de tiempo Unix en milisegundos. Codifica el tiempo de generación con precisión de 1 ms. Cubre fechas hasta el año 10889.80 bits — datos aleatorios criptográficamente seguros. Regenerados de forma fresca para cada ULID (a menos que se use el modo de monotonía).

Codificado como 26 caracteres Crockford Base32: los primeros 10 caracteres representan la marca de tiempo, los últimos 16 representan el componente aleatorio.

Alfabeto Crockford Base32

Los ULIDs usan la codificación Crockford Base32, que usa 32 de los 36 caracteres alfanuméricos. El alfabeto es: 0123456789ABCDEFGHJKMNPQRSTVWXYZ

¿Por qué estos 32 caracteres?
0123456789ABCDEFGHJKMNPQRSTVWXYZ

Cuatro caracteres se excluyen intencionalmente:

  • I y L se excluyen — fácilmente confundidos con el dígito 1
  • O se excluye — fácilmente confundida con el dígito 0
  • U se excluye — evita palabras obscenas accidentales en los IDs generados
  • La codificación es insensible a mayúsculas01ARZ3NDEKTSV4RRFFQ69G5FAV y 01arz3ndektsv4rrffq69g5fav son el mismo ULID

Crockford Base32 es más eficiente que el hexadecimal (32 símbolos vs 16) y más legible para humanos que Base64 (sin caracteres + / =, insensible a mayúsculas).

ULID vs UUID

ULIDs y UUIDs ambos representan identificadores de 128 bits, pero difieren significativamente en codificación y objetivos de diseño:

PropiedadULIDUUID
FormatoCrockford Base32Hexadecimal con guiones
Longitud26 caracteres36 caracteres
Marca de tiempoUnix ms de 48 bitsNinguno (v4) o ms de 48 bits (v7)
OrdenableSí — lexicográficoNo (v4) / Sí (v7)
Seguro para URLSí (solo alfanumérico)Sí (con guiones)
DependenciasRequiere bibliotecaNativo (crypto.randomUUID)
Soporte BDAlmacenar como CHAR(26) o BINARY(16)Tipo de columna UUID nativo
EspecificaciónEspecificación comunitaria (ulid.github.io)RFC 4122 / RFC 9562

Si ya está en un ecosistema UUID (columnas uuid de PostgreSQL, APIs REST, ORMs con soporte UUID), UUID v7 generalmente es una mejor opción que ULID. Si prefiere una codificación más amigable para humanos y controla la pila completa, ULID es una excelente elección.

ULID vs nanoid

Tanto ULID como nanoid producen identificadores cortos y seguros para URL, pero tienen diferentes objetivos de diseño:

PropiedadULIDNanoID
Marca de tiempoSí — Unix ms de 48 bitsNo
OrdenableNo
Longitud predeterminada26 caracteres21 caracteres
Entropía80 bits (componente aleatorio)~126 bits
AlfabetoCrockford Base32 (32 caracteres)Base64 seguro para URL (64 caracteres)
Longitud personalizableNoSí (cualquier longitud)
Caso de usoIDs ordenados por tiempo, claves primarias BDTokens aleatorios, URLs cortas, claves API

Elija ULID cuando necesite ordenación temporal. Elija nanoid cuando necesite máxima entropía en una cadena aleatoria corta.

Usando ULIDs en Bases de Datos

Los ULIDs pueden almacenarse en bases de datos de varias formas según sus requisitos:

Almacenar como CHAR(26)
El enfoque más sencillo. Se preserva el orden de clasificación lexicográfico. Ligeramente más grande que el almacenamiento binario pero legible para humanos y fácil de depurar.
Almacenar como BINARY(16)
Decodifique el ULID a su representación binaria de 16 bytes para almacenamiento compacto. Requiere codificación/decodificación en el código de la aplicación. Se preserva el orden de clasificación.
PostgreSQL
Almacene como CHAR(26) o use el tipo bytea para almacenamiento binario. No hay tipo ULID nativo, pero la ordenación lexicográfica en CHAR(26) funciona correctamente.
MySQL / MariaDB
Use CHAR(26) CHARACTER SET ascii para almacenamiento eficiente. El almacenamiento binario en BINARY(16) también funciona y ahorra espacio.
SQLite
Almacene como TEXT. La comparación de texto predeterminada de SQLite ordena los ULIDs correctamente debido a su diseño lexicográfico.
MongoDB
Almacene como campo de cadena. La ordenabilidad lexicográfica de ULID funciona naturalmente con la comparación de cadenas de MongoDB.

Ejemplos de Código

La generación de ULID requiere la biblioteca ulid (disponible para JavaScript, Python, Go, Rust y más):

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

Preguntas Frecuentes

¿Son los ULIDs globalmente únicos?
Sí — con muy alta probabilidad. El componente aleatorio de 80 bits proporciona 2^80 ≈ 1,2 × 10^24 valores posibles por milisegundo por generador. La probabilidad de una colisión dentro del mismo milisegundo entre diferentes generadores es insignificante para cualquier sistema práctico. Para garantías de unicidad estrictas, use el modo monotónico, que incrementa el componente aleatorio para IDs generados dentro del mismo milisegundo.
¿Es un ULID lo mismo que un UUID?
No — ULIDs y UUIDs son diferentes codificaciones de un valor de 128 bits. Un ULID no puede sustituirse directamente por un UUID en sistemas que validan el formato UUID (hexadecimal con guiones). Sin embargo, puede convertir entre representaciones ULID binario y UUID si es necesario.
¿Cómo funciona el modo monotónico de ULID?
En el modo estándar, el componente aleatorio de 80 bits se genera fresco para cada ULID. En el modo monotónico, cuando se generan múltiples ULIDs dentro del mismo milisegundo, el componente aleatorio del segundo y siguientes IDs es el valor aleatorio anterior más uno. Esto garantiza un ordenamiento monótono estricto dentro de un milisegundo en un único generador.
¿Puedo decodificar un ULID para obtener la marca de tiempo de generación?
Sí. Los primeros 10 caracteres Crockford Base32 codifican la marca de tiempo Unix de 48 bits en milisegundos. Decodifique esos caracteres usando el alfabeto Crockford Base32, interprete el resultado como una marca de tiempo Unix en milisegundos y convierta a una fecha. Esta herramienta hace exactamente eso.
¿Es ULID un estándar oficial?
No. ULID es una especificación comunitaria mantenida en ulid.github.io. No es un estándar IETF como UUID. Esto significa que no hay un RFC oficial al que hacer referencia, y las implementaciones pueden variar ligeramente. UUID v7 (RFC 9562, 2024) es la alternativa estandarizada por IETF con propiedades similares de ordenación temporal.