UUID v4 vs v7 vs ULID: Cómo elegir el identificador adecuado para tu base de datos

Estás iniciando un nuevo servicio, y la primera decisión es engañosamente simple: ¿cómo debería ser tu clave primaria? Los enteros auto-incrementales filtran el número de filas, exponen el orden de creación y dejan de funcionar en el momento en que necesitas fusionar datos entre bases de datos. Los UUIDs resuelven esos problemas, pero ahora tienes que elegir cuál UUID.

UUID v4 ha sido la opción por defecto durante más de una década. UUID v7, estandarizado en RFC 9562 en mayo de 2024, promete mejor rendimiento en bases de datos mediante ordenación temporal. Y ULID, la alternativa impulsada por la comunidad desde 2016, ofrece beneficios similares en un formato más compacto. Cada uno tiene compromisos reales que afectan el rendimiento, la privacidad y la mantenibilidad a largo plazo.

Esta guía compara los tres, con datos reales de benchmarks, consejos prácticos de migración y un marco de decisión claro para 2026.

¿Qué es un UUID? (Y por qué “GUID” es lo mismo)

Un UUID (Universally Unique Identifier, identificador universalmente único) es un valor de 128 bits diseñado para ser único sin necesidad de una autoridad central. El formato estándar consiste en 32 caracteres hexadecimales separados por guiones: 550e8400-e29b-41d4-a716-446655440000.

Si has trabajado con .NET o Windows, los habrás visto llamados GUIDs (Globally Unique Identifiers). Son exactamente lo mismo: GUID es el nombre que Microsoft le da al estándar UUID. La disposición de bits, los algoritmos de generación y los requisitos de almacenamiento son idénticos.

UUID ha pasado por varias versiones. Las que importan hoy:

VersiónEstrategiaEstandarizado¿Sigue siendo relevante?
v1Marca temporal + dirección MACRFC 4122 (2005)Mayormente reemplazado por v7
v4AleatorioRFC 4122 (2005)Sí — la opción por defecto actual
v5Basado en nombre (hash SHA-1)RFC 4122 (2005)Casos de uso específicos
v7Marca temporal + aleatorioRFC 9562 (2024)Sí — la nueva recomendación

RFC 9562 es explícito sobre la dirección: “Las implementaciones DEBERÍAN utilizar UUIDv7 en lugar de UUIDv1 y UUIDv6 si es posible.”

UUID v4: El estándar aleatorio

UUID v4 genera identificadores a partir de 122 bits de aleatoriedad criptográficamente segura. Eso supone un espacio de claves de aproximadamente 5,3 × 10³⁶ valores posibles: necesitarías generar mil millones de UUIDs por segundo durante 86 años para alcanzar una probabilidad de colisión del 50%.

Cómo funciona: 128 bits en total, con 6 bits reservados para los marcadores de versión (4) y variante. Los 122 bits restantes provienen de un CSPRNG como crypto.getRandomValues().

Ejemplo: f47ac10b-58cc-4372-a567-0e02b2c3d479

La simplicidad es su fortaleza. No requiere coordinación, no filtra marcas temporales, no necesita mantener estado. Todos los lenguajes principales y bases de datos tienen soporte nativo para v4.

El problema: los UUIDs aleatorios fragmentan tu base de datos

La aleatoriedad pura tiene un coste. Cuando insertas UUIDs aleatorios en un índice B-tree (el tipo por defecto en PostgreSQL, MySQL y la mayoría de bases de datos relacionales), las nuevas filas aterrizan en posiciones arbitrarias del árbol. Esto provoca:

  • Divisiones de página: La base de datos constantemente divide y reorganiza las páginas del índice en lugar de añadir al final.
  • Amplificación de escritura: Los benchmarks de EnterpriseDB muestran que los UUIDs aleatorios generan 8 veces más WAL (write-ahead log) que las alternativas secuenciales: 20 GB frente a 2,5 GB para la misma carga de trabajo.
  • Caída del rendimiento: En conjuntos de datos más grandes que la RAM, las inserciones con UUID aleatorio caen al 20-30% del rendimiento de UUIDs secuenciales.
  • Espacio desperdiciado: PlanetScale informa que los UUIDs aleatorios hacen que la utilización de páginas del B+ tree en MySQL caiga al ~50%, comparado con el 94% con claves secuenciales.

Esto no es una preocupación teórica. Buildkite observó una reducción del 50% en la tasa de WAL en su base de datos principal tras cambiar a UUIDs ordenados temporalmente. Shopify midió una disminución del 50% en la duración de INSERT al pasar de UUID v4 a identificadores ordenados temporalmente para las claves de idempotencia del sistema de pagos.

UUID v4 funciona bien para tablas pequeñas, escrituras infrecuentes, o cualquier caso donde no uses el UUID como clave primaria. Para sistemas de alto rendimiento, el coste de la fragmentación se acumula con el tiempo.

UUID v7: Ordenado temporalmente y amigable con bases de datos

UUID v7 resuelve el problema de la fragmentación colocando una marca temporal al principio. Los 48 bits más significativos codifican una marca temporal de época UNIX en milisegundos, seguidos de ~74 bits de aleatoriedad criptográficamente segura.

Cómo funciona:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
├─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤
|                       unix_ts_ms (48 bits)                        |
├─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤
|  unix_ts_ms   | ver |          rand_a (12 bits)                   |
├─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤
|var|                      rand_b (62 bits)                         |
├─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤

Como los UUIDs generados en el mismo milisegundo comparten un prefijo de marca temporal, se agrupan en los índices B-tree. Las nuevas inserciones se añaden cerca del final del árbol en lugar de dispersarse aleatoriamente, el mismo patrón de acceso que hace rápidos a los enteros auto-incrementales.

Ejemplo: 019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91 — los primeros 12 caracteres hexadecimales codifican el momento de creación.

Lo que cambió RFC 9562

Antes de RFC 9562, los UUIDs ordenados temporalmente existían solo como propuestas informales. El RFC, publicado en mayo de 2024, convirtió UUID v7 en un estándar oficial del IETF con una disposición de bits definida. Cataloga 16 implementaciones diferentes no estándar de IDs ordenados temporalmente, incluyendo ULID, Snowflake de Twitter y ShardId de Instagram, que motivaron su creación.

El impacto práctico: los autores de bibliotecas ahora tienen una única especificación contra la cual implementar, y las bases de datos están añadiendo soporte nativo. PostgreSQL 18 (lanzado a finales de 2025) incluyó una función nativa uuidv7(), eliminando la necesidad de extensiones o generación a nivel de aplicación.

La función nativa uuidv7() de PostgreSQL 18

PostgreSQL 18, lanzado a finales de 2025, añade dos nuevas funciones:

-- Generar un UUID v7 ordenado temporalmente
SELECT uuidv7();
-- Resultado: 019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91

-- Generar un UUID v4 aleatorio (alias de gen_random_uuid())
SELECT uuidv4();

La implementación de PostgreSQL añade una fracción de marca temporal sub-milisegundo de 12 bits, proporcionando mejor ordenación monótona dentro de un mismo proceso backend. Esto significa que incluso las filas insertadas en el mismo milisegundo mantienen el orden de creación, algo importante para tablas de alto rendimiento.

Para versiones anteriores de PostgreSQL, puedes generar UUID v7 a nivel de aplicación o usar extensiones como pg_idkit.

UUID v4 vs v7: Comparación directa

PropiedadUUID v4UUID v7
Formato128 bits, 36 caracteres hex128 bits, 36 caracteres hex
Bits aleatorios122~74
Ordenable por fecha de creaciónNoSí (precisión de ms)
Rendimiento de índice B-treeDeficiente a escalaExcelente
Filtración de marca temporalNingunaSí (precisión de ms)
Estándar RFCRFC 4122 / RFC 9562RFC 9562 (mayo 2024)
Soporte nativo en BDTodas las principalesPostgreSQL 18+, en crecimiento
Soporte en bibliotecasUniversalAmplio y en crecimiento
Tamaño de almacenamiento16 bytes (binario)16 bytes (binario)
Compatibilidad de tipo de columnauuid / BINARY(16)uuid / BINARY(16) — misma columna, totalmente compatible

El dato clave: v4 y v7 son compatibles a nivel de columna. Usan el mismo tipo de dato uuid, el mismo almacenamiento binario de 16 bytes, la misma representación de cadena de 36 caracteres. Puedes almacenar ambos en la misma columna, lo que hace que la migración incremental sea sencilla.

Pruébalo tú mismo: UUID Generator — genera identificadores UUID v4 al instante en tu navegador, con generación masiva y copia con un clic.

UUID v7 vs ULID: ¿Todavía necesitas ULID?

ULID (Universally Unique Lexicographically Sortable Identifier) se lanzó en 2016 para resolver el mismo problema que UUID v7 ahora aborda: identificadores ordenados temporalmente y globalmente únicos. Así se comparan:

PropiedadUUID v7ULID
Codificación36 caracteres hex con guiones26 caracteres Crockford Base32
Marca temporal48 bits ms epoch48 bits ms epoch
Bits aleatorios~7480
EstándarIETF RFC 9562Especificación comunitaria (sin RFC)
Ordenación monótonaDepende de la implementaciónIncremento definido en la especificación dentro del mismo ms
Tipo en base de datosColumna nativa uuidRequiere CHAR(26) o BINARY(16)
Seguro para URLsNo (guiones)Sí (Base32)
Marca temporal válida hastaAño 10889Año 10889

Dónde gana UUID v7

  1. Estandarización. UUID v7 tiene un RFC del IETF. Cada base de datos, ORM y entorno de ejecución ya entiende el tipo UUID. ULID requiere análisis personalizado en la mayoría de ecosistemas.

  2. Soporte nativo en bases de datos. Los ULIDs no caben en la columna nativa uuid de PostgreSQL sin conversión. O los almacenas como cadenas (desperdiciando espacio) o los conviertes a binario (perdiendo la codificación Crockford). UUID v7 encaja directamente en las columnas uuid existentes.

  3. Impulso del ecosistema. Bytebase predice que la industria “abandonará gradualmente las soluciones propietarias y convergirá en UUIDv7 como clave primaria para la mayoría de los casos de uso.” La función nativa uuidv7() de PostgreSQL 18 acelera esta tendencia.

Dónde ULID todavía tiene sentido

  1. Representación compacta. Con 26 caracteres frente a 36, los ULIDs son más cortos en URLs y APIs. Si la longitud de la cadena importa para tu caso de uso, ULID es más compacto.

  2. Ligeramente más aleatoriedad. ULID proporciona 80 bits aleatorios frente a los ~74 de UUID v7. En la práctica, ambos tienen tasas de colisión astronómicamente bajas, pero ULID tiene un componente aleatorio marginalmente mayor.

  3. Infraestructura ULID existente. Si tu sistema ya usa ULIDs y el coste de migración es significativo, no hay razón urgente para cambiar. Ambos proporcionan un rendimiento comparable en bases de datos ya que comparten el mismo prefijo de marca temporal de 48 bits.

Para nuevos proyectos en 2026, UUID v7 es la elección más segura. Está estandarizado, tiene soporte nativo en bases de datos y no requiere que tu equipo mantenga lógica de análisis de ULID.

Rendimiento en bases de datos: Benchmarks reales

La diferencia de rendimiento entre identificadores aleatorios y ordenados temporalmente está bien documentada en sistemas en producción:

PostgreSQL

MétricaUUID v4UUID v7 / Secuencial
Rendimiento de INSERT (dataset grande)20-30% de la línea base100% de la línea base
Volumen de WAL~20 GB~2,5 GB
Tasa de aciertos en caché85%99%

Fuente: Benchmark de EnterpriseDB. La diferencia se amplía a medida que los conjuntos de datos superan la RAM disponible.

MySQL / InnoDB

El motor InnoDB de MySQL usa índices agrupados (clustered indexes), donde la clave primaria determina el orden físico de las filas. Los UUIDs aleatorios son especialmente costosos:

  • La utilización de páginas del B+ tree cae al ~50% (frente al 94% secuencial)
  • UUID almacenado como CHAR(36) es 9 veces más grande que un entero de 32 bits
  • BINARY(16) es el formato de almacenamiento recomendado: 4 veces más grande que un entero, pero lo suficientemente compacto para la mayoría de las cargas de trabajo

Fuente: Análisis de PlanetScale.

Cuándo mantener auto-increment

Los UUIDs no siempre son la respuesta. Los enteros auto-incrementales siguen siendo la elección correcta cuando:

  • Operas una sola base de datos sin planes de sharding
  • El rendimiento de escritura importa más que la unicidad global
  • El recuento de filas no es información sensible
  • No necesitas generar IDs fuera de la base de datos

Para sistemas distribuidos, microservicios, o cualquier arquitectura donde los IDs deben generarse a nivel de aplicación, UUID v7 te ofrece tanto el rendimiento de claves secuenciales como la flexibilidad de la generación descentralizada.

Cómo generar UUID v7

JavaScript / TypeScript

// Using the 'uuid' package (v10+)
import { v7 as uuidv7 } from 'uuid';
const id = uuidv7(); // '019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91'

Python

# Python 3.x with uuid7 package
from uuid_extensions import uuid7
id = str(uuid7())  # '019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91'

Go

// Using github.com/gofrs/uuid/v5
import "github.com/gofrs/uuid/v5"
id, _ := uuid.NewV7()
fmt.Println(id.String()) // "019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91"

PostgreSQL 18+

-- Native function, no extension needed
CREATE TABLE orders (
  id uuid PRIMARY KEY DEFAULT uuidv7(),
  customer_id uuid NOT NULL,
  created_at timestamptz DEFAULT now()
);

Otros lenguajes

Las bibliotecas de UUID v7 están disponibles para Rust (crate uuid v1.4+), Java (uuid-creator), C# (UUIDNext) y PHP (symfony/uid).

Migrar de UUID v4 a v7

¿Ya tienes UUID v4 en producción? La buena noticia: la migración no requiere un cambio radical de una sola vez.

v4 y v7 pueden coexistir

Ambas versiones comparten el mismo tipo de columna uuid y la misma representación binaria de 16 bytes. Puedes empezar a generar v7 para filas nuevas mientras las filas v4 existentes permanecen intactas. Las consultas, joins e índices funcionan de forma idéntica: a la base de datos no le importa qué versión de UUID es.

La única diferencia de comportamiento: las nuevas filas v7 se ordenarán después de las filas v4 más antiguas cuando se ordenen por clave primaria, ya que el prefijo de marca temporal de v7 las coloca más adelante en el orden lexicográfico. Si tu aplicación depende del ordenamiento de UUIDs (algo que no debería ocurrir con v4), verifica esta suposición.

Lista de verificación para la migración

  1. Actualiza la generación de IDs — cambia la generación de UUIDs a nivel de aplicación a v7. Para PostgreSQL 18+, cambia el valor por defecto de la columna a uuidv7().
  2. Actualiza los ORMs — la mayoría de los ORMs delegan la generación de UUIDs a la aplicación o la base de datos. Actualiza el generador, no el tipo de columna.
  3. Monitoriza el rendimiento de los índices — después del cambio, las nuevas inserciones serán secuenciales. Con el tiempo, tus índices se volverán naturalmente más eficientes a medida que las filas v7 predominen.
  4. No hagas backfill — convertir los valores v4 existentes a v7 es innecesario y rompería las referencias de clave foránea. Deja que v4 y v7 coexistan.

Consideraciones de privacidad: Marcas temporales en tus IDs

UUID v7 codifica el momento de creación con precisión de milisegundos. Cualquiera que pueda ver el UUID puede extraer cuándo fue creado. Para claves internas de base de datos, esto rara vez es una preocupación. Pero considera las implicaciones para:

  • APIs públicas — si tu API expone los IDs de las entidades, los clientes pueden determinar cuándo se crearon los recursos. Esto podría revelar patrones de negocio (volumen de pedidos, tasa de crecimiento de usuarios).
  • Tokens de sesión y claves de API — prefiere UUID v4 para secretos. La marca temporal en v7 no aporta valor para tokens y revela información temporal innecesariamente.
  • Cumplimiento normativo — dependiendo de tu jurisdicción, las marcas temporales de creación incrustadas en identificadores podrían constituir datos personales si pueden vincularse a un usuario.

Un enfoque práctico: usa UUID v7 para claves primarias de base de datos (internas), UUID v4 para tokens y claves de API visibles externamente.

Pruébalo tú mismo: UUID Generator — ¿necesitas un lote de UUIDs para pruebas? Genera hasta 25 a la vez, copia individualmente o descarga como archivo de texto.

Preguntas frecuentes

¿Pueden dos UUIDs ser iguales alguna vez?

Teóricamente sí, pero en la práctica no. Los 122 bits aleatorios de UUID v4 ofrecen un espacio de claves de 5,3 × 10³⁶. Necesitarías generar mil millones de UUIDs por segundo durante 86 años para alcanzar una probabilidad de colisión del 50%. UUID v7 tiene menos bits aleatorios (~74), pero las colisiones dentro del mismo milisegundo siguen siendo astronómicamente improbables.

¿Debo almacenar los UUIDs como cadenas o binario?

Binario. Un UUID almacenado como CHAR(36) usa 36 bytes; como BINARY(16) usa 16 bytes, menos de la mitad del almacenamiento. El tipo nativo uuid de PostgreSQL se almacena como binario de 16 bytes automáticamente. En MySQL, usa BINARY(16) y convierte a nivel de aplicación. PlanetScale señala que CHAR(36) es 9 veces más grande que un entero de 32 bits, lo que hace esencial el almacenamiento binario para tablas grandes.

¿Cómo se compara UUID v7 con Twitter Snowflake?

Ambos son identificadores distribuidos ordenados temporalmente, pero sirven para necesidades diferentes. Los IDs Snowflake son de 64 bits (más pequeños, más rápidos de comparar), pero requieren un servicio de coordinación central para asignar IDs de worker. UUID v7 es de 128 bits y no requiere coordinación: cualquier nodo puede generar uno de forma independiente. RFC 9562 lista explícitamente Snowflake entre las 16 implementaciones no estándar que motivaron la creación de UUID v7.

¿Cómo genero UUID v7 en PostgreSQL antes de la versión 18?

Antes del soporte nativo, tienes varias opciones: la extensión pg_idkit, generación a nivel de aplicación (generar en tu código y pasar a la base de datos), o una función PL/pgSQL que ensamble la marca temporal y los bytes aleatorios manualmente. Actualizar a PostgreSQL 18 es la opción más limpia si tu infraestructura lo permite.

¿Es UUID v7 seguro para claves de API?

No — usa UUID v4 para secretos. La marca temporal de UUID v7 revela cuándo se creó la clave, lo cual es información innecesaria en un contexto de seguridad. Para claves de API y tokens de sesión, necesitas máxima entropía sin metadatos incrustados. Los 122 bits de aleatoriedad pura de un CSPRNG de UUID v4 son apropiados, aunque los formatos de token dedicados pueden ofrecer funcionalidades adicionales como expiración incorporada.

¿Cuál deberías elegir? Un marco de decisión

Elige UUID v4 cuando:

  • Necesites máxima aleatoriedad (tokens, claves de API, IDs de sesión)
  • El momento de creación deba permanecer privado
  • Estés añadiendo UUIDs a una tabla pequeña con pocas escrituras donde la fragmentación del índice no importa

Elige UUID v7 cuando:

  • El UUID sirva como clave primaria de la base de datos
  • Necesites ordenación temporal sin una columna extra created_at
  • El rendimiento de escritura importe a escala
  • Quieras los beneficios de claves secuenciales sin una autoridad central

Elige ULID cuando:

  • Necesites una representación de cadena más corta (26 caracteres frente a 36)
  • Tu sistema ya funcione con infraestructura ULID
  • Necesites identificadores seguros para URLs sin codificación

Para la mayoría de los nuevos proyectos en 2026, UUID v7 es la recomendación por defecto. Combina la generación descentralizada de UUID v4 con el rendimiento en bases de datos de claves secuenciales, respaldado por un estándar del IETF y un soporte nativo en bases de datos en crecimiento. La convergencia hacia v7 está en marcha: la función nativa uuidv7() de PostgreSQL 18 es la señal más clara hasta ahora.

Sea cual sea tu elección, puedes generar identificadores UUID v4 al instante con el UUID Generator, o formatear tus respuestas de API que contengan UUIDs con el JSON Formatter.