Saltar al contenido

Generador de ULID - Crea Identificadores Únicos Ordenables Gratis en Línea

Herramienta gratuita de generación de ULID que crea identificadores únicos y ordenables al instante. Genere ULID criptográficamente seguros para bases de datos, API y sistemas distribuidos en línea.

Generador de ULID

Introduce un valor para ver los resultados
Calculadora de carga...
📚

Documentación

¿Qué es un ULID?

Un ULID (Universally Unique Lexicographically Sortable Identifier, es decir, identificador único universal ordenable lexicográficamente) es un código de 26 caracteres que se usa para etiquetar registros en una base de datos o un evento en un sistema distribuido. Combina la hora actual con datos aleatorios, de modo que una lista de ULID ordenada alfabéticamente queda ordenada por el momento en que se creó cada uno. Un generador de ULID es una herramienta que produce estos códigos.

Estructura de un ULID

Un ULID tiene dos partes, escritas una a continuación de la otra sin separador:

  • Marca de tiempo (10 caracteres): el número de milisegundos transcurridos desde el 1 de enero de 1970 (la época Unix), almacenado como un entero de 48 bits.
  • Aleatoriedad (16 caracteres): 80 bits de datos aleatorios, añadidos para que dos ULID creados en el mismo milisegundo sigan siendo casi con certeza distintos.

Ambas partes se escriben con el alfabeto Base32 de Crockford: los dígitos 0-9 y las letras A-Z, menos las letras I, L, O y U. La I y la L pueden confundirse con el dígito 1, y la O con el dígito 0. La U se omite para evitar palabras obscenas accidentales. El resultado es una cadena corta, fácil de leer en voz alta y segura para incluir directamente en una URL.

Cómo calcular un ULID

Un generador de ULID construye un identificador en tres pasos.

  1. Leer la hora actual en milisegundos desde la época Unix. Es un número de 48 bits.
  2. Generar 80 bits de datos aleatorios, normalmente con un generador de números aleatorios criptográficamente seguro, lo que da 10 bytes aleatorios.
  3. Codificar ambas partes por separado con el alfabeto Base32 de Crockford: la marca de tiempo de 48 bits se convierte en 10 caracteres, y el valor aleatorio de 80 bits se convierte en 16 caracteres. Las dos cadenas codificadas se unen para formar el ULID final de 26 caracteres.

La codificación funciona leyendo el número en grupos de 5 bits, porque cada carácter Base32 representa uno de 32 valores posibles (2^5 = 32). Diez caracteres admiten hasta 50 bits, lo que deja espacio suficiente para la marca de tiempo de 48 bits. Dieciséis caracteres admiten exactamente 80 bits, lo que coincide con la parte de aleatoriedad sin que sobre nada.

Ejemplo resuelto

Supongamos que un generador de ULID se ejecuta con la marca de tiempo 1712345678901 (milisegundos desde la época) y obtiene los bytes aleatorios [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].

Paso 1: codificar la marca de tiempo. Se divide 1712345678901 repetidamente entre 32, tomando el resto cada vez y leyendo los dígitos del último al primero (es la conversión de base estándar). Esto produce la cadena de 10 caracteres 01HTQW311N.

Paso 2: codificar la aleatoriedad. Se agrupan los 10 bytes aleatorios en un flujo de 80 bits y luego se leen en grupos de 5 bits, convirtiendo cada fragmento de 5 bits en un carácter Base32. Esto produce la cadena de 16 caracteres 1KR5G0Y75M3EF00H.

Paso 3: unir las partes. El ULID final es:

101HTQW311N 1KR5G0Y75M3EF00H
2

escrito sin el espacio: 01HTQW311N1KR5G0Y75M3EF00H, 26 caracteres en total.

ULID frente a UUID

CaracterísticaULIDUUID (versión 4)
Longitud26 caracteres36 caracteres (con guiones)
Ordenable por fecha de creaciónSíNo
CodificaciónBase32 de CrockfordHexadecimal
Contiene una marca de tiempoSí (48 bits)No
Seguro para URL sin necesidad de escapeSíSí

Ambos formatos buscan producir identificadores únicos entre sistemas sin que una autoridad central reparta los números. La principal diferencia práctica es el orden: como un ULID empieza con una marca de tiempo, ordenar los ULID como texto simple también los ordena por tiempo. Un UUID aleatorio no tiene esta propiedad, ya que todas sus partes son aleatorias.

Usos habituales

  • Claves primarias de bases de datos: los ULID permiten que una base de datos indexe las filas nuevas aproximadamente en el orden en que se insertaron, algo que muchos motores de bases de datos manejan con más eficiencia que las claves totalmente aleatorias.
  • Sistemas distribuidos: cada servidor puede generar ULID de forma independiente, sin coordinarse con un contador central, y los resultados siguen siendo casi con certeza únicos.
  • Registros de eventos: como los ULID se ordenan por tiempo, una lista de identificadores de eventos puede servir como una cronología aproximada.
  • Identificadores de API y de archivos: el formato fijo de 26 caracteres y seguro para URL funciona bien en direcciones web y nombres de archivo.

Entre los formatos de identificador relacionados están KSUID, que también codifica una marca de tiempo para ordenar, y los ID Snowflake, usados por Twitter y otros, que combinan una marca de tiempo, un identificador de máquina y un contador.

Ejemplos de código

Cada ejemplo siguiente construye un ULID como describe la especificación de ULID: codifica la marca de tiempo de 48 bits como 10 caracteres Base32 de Crockford, codifica 80 bits de aleatoriedad como otros 16 y los une.

JavaScript

1const ENCODING_CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
2
3function encodeULID(time, randomBytes) {
4  // Timestamp: 48 bits -> 10 characters
5  let timestampStr = '';
6  let t = time;
7  for (let i = 0; i < 10; i++) {
8    timestampStr = ENCODING_CHARS[t % 32] + timestampStr;
9    t = Math.floor(t / 32);
10  }
11
12  // Randomness: 80 bits -> 16 characters
13  let result = timestampStr;
14  let bits = 0;
15  let bitCount = 0;
16  for (let i = 0; i < 10; i++) {
17    bits = (bits << 8) | randomBytes[i];
18    bitCount += 8;
19    while (bitCount >= 5) {
20      bitCount -= 5;
21      result += ENCODING_CHARS[(bits >> bitCount) & 0x1f];
22    }
23  }
24  return result;
25}
26
27function generateULID() {
28  const randomBytes = crypto.getRandomValues(new Uint8Array(10));
29  return encodeULID(Date.now(), randomBytes);
30}
31
32console.log(generateULID());
33

Python

1import os
2import time
3
4ENCODING_CHARS = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
5
6def encode_ulid(time_ms, random_bytes):
7    # Timestamp: 48 bits -> 10 characters
8    chars = []
9    t = time_ms
10    for _ in range(10):
11        chars.append(ENCODING_CHARS[t % 32])
12        t //= 32
13    timestamp_part = "".join(reversed(chars))
14
15    # Randomness: 80 bits -> 16 characters
16    bits = 0
17    bit_count = 0
18    random_part = []
19    for byte in random_bytes:
20        bits = (bits << 8) | byte
21        bit_count += 8
22        while bit_count >= 5:
23            bit_count -= 5
24            random_part.append(ENCODING_CHARS[(bits >> bit_count) & 0x1F])
25
26    return timestamp_part + "".join(random_part)
27
28def generate_ulid():
29    return encode_ulid(int(time.time() * 1000), os.urandom(10))
30
31print(generate_ulid())
32

Java

1import java.security.SecureRandom;
2import java.time.Instant;
3
4public class ULIDGenerator {
5    private static final SecureRandom random = new SecureRandom();
6    private static final char[] ENCODING_CHARS =
7        "0123456789ABCDEFGHJKMNPQRSTVWXYZ".toCharArray();
8
9    public static String generateULID() {
10        long timestamp = Instant.now().toEpochMilli();
11        byte[] randomBytes = new byte[10];
12        random.nextBytes(randomBytes);
13
14        // Timestamp: 48 bits -> 10 characters
15        char[] timestampChars = new char[10];
16        long t = timestamp;
17        for (int i = 9; i >= 0; i--) {
18            timestampChars[i] = ENCODING_CHARS[(int) (t % 32)];
19            t /= 32;
20        }
21
22        // Randomness: 80 bits -> 16 characters
23        StringBuilder result = new StringBuilder(new String(timestampChars));
24        long bits = 0;
25        int bitCount = 0;
26        for (byte b : randomBytes) {
27            bits = (bits << 8) | (b & 0xFF);
28            bitCount += 8;
29            while (bitCount >= 5) {
30                bitCount -= 5;
31                result.append(ENCODING_CHARS[(int) ((bits >> bitCount) & 0x1F)]);
32            }
33        }
34        return result.toString();
35    }
36
37    public static void main(String[] args) {
38        System.out.println(generateULID());
39    }
40}
41

Preguntas frecuentes

¿Para qué se usa un ULID? Un ULID se usa como identificador único de una fila de base de datos, de un recurso de API o de un evento registrado, en los casos en que también resulta útil ordenar por hora de creación.

¿Qué longitud tiene un ULID? Un ULID siempre tiene 26 caracteres: 10 para la marca de tiempo y 16 para la parte aleatoria.

¿Qué codificación usa un ULID? Un ULID usa el alfabeto Base32 de Crockford, formado por los dígitos 0-9 y las letras A-Z sin la I, la L, la O y la U, para evitar lecturas erróneas y palabras accidentales.

¿En qué se diferencia un ULID de un UUID? Un ULID se ordena por hora de creación y tiene 26 caracteres. Un UUID aleatorio (versión 4) no se ordena por tiempo y tiene 36 caracteres, contando los guiones.

¿Qué probabilidad hay de una colisión entre dos ULID? Los 80 bits de aleatoriedad hacen que las colisiones sean extremadamente improbables. Habría que generar aproximadamente 1,3 billones de ULID dentro del mismo milisegundo para alcanzar una probabilidad del 50 % de que dos coincidan.

¿Se pueden generar ULID sin conexión a internet? Sí. Un ULID solo necesita el reloj local y un generador de números aleatorios, por lo que puede crearse totalmente sin conexión.

Referencias

  1. ULID project. Universally Unique Lexicographically Sortable Identifier. Especificación de ULID: marca de tiempo de 48 bits en milisegundos, 80 bits de aleatoriedad, forma canónica de 10 + 16 caracteres, alfabeto Base32 de Crockford.
  2. Douglas Crockford. Base 32. Base32 de Crockford: el alfabeto de 32 símbolos y por qué se excluyen la I, la L, la O y la U.