Toolbit
Guías

UUID v4 vs v7: cuál usar y por qué importa en la base de datos

Cómo están construidos los UUID v4 y v7, por qué v7 mantiene compactos los índices de la base de datos, qué revela cada versión y cómo se comparan con ULID, Snowflake y los autoincrementales.

Por Javier VallejoPublicado el 6 min de lectura

El problema que resuelven los UUID

La forma más simple de identificar registros es un número que crece de a uno: el primer usuario es el 1, el segundo es el 2. Funciona bien mientras haya una sola base de datos que asigne los números. En cuanto los identificadores se generan en varios lugares a la vez (varios servidores, aplicaciones móviles que crean registros sin conexión, servicios que se comunican por colas de mensajes), hace falta coordinación para no repetir números, y esa coordinación es lenta, frágil o directamente imposible.

Los UUID eliminan la coordinación: cualquier proceso puede generar un identificador de 128 bits por su cuenta, con una probabilidad de colisión tan baja que se puede ignorar. Durante años, la opción por defecto fue el UUID v4, completamente aleatorio. Desde la publicación del RFC 9562 en 2024, el UUID v7 se volvió la alternativa recomendada para muchos casos. Esta guía explica cómo está construido cada uno, por qué la diferencia importa en una base de datos y qué revela cada formato. Para generar o inspeccionar UUID, el generador de UUID trabaja con ambas versiones.

Cómo están construidos

Los dos ocupan 128 bits y comparten dos campos fijos: 4 bits de versión y 2 bits de variante. La diferencia está en qué ocupa el resto.

UUID v4: los 122 bits restantes son aleatorios. No contiene ninguna información: ni cuándo se creó ni dónde.

xxxxxxxx-xxxx-4xxx-Vxxx-xxxxxxxxxxxx
               │    └─ variante (8, 9, a o b)
               └────── versión 4
x = 122 bits aleatorios

UUID v7: los primeros 48 bits son un timestamp Unix en milisegundos, y el resto, salvo versión y variante, son 74 bits aleatorios (o en parte un contador, si se generan varios en el mismo milisegundo).

tttttttt-tttt-7rrr-Vrrr-rrrrrrrrrrrr
└─────────┘    │
 48 bits de timestamp (ms desde 1970)
r = 74 bits aleatorios o contador

Un ejemplo del propio RFC 9562 es 017f22e2-79b0-7cc3-98c4-dc0c0c07398f. Los primeros 12 dígitos hexadecimales, 017f22e279b0, son el número 1645557742000: los milisegundos transcurridos desde 1970 hasta el 22 de febrero de 2022 a las 19:22:22 UTC. Cualquiera que tenga el UUID puede leer ese dato, como muestra el conversor de timestamp.

Por qué v7 es mejor para los índices

La mayoría de las bases de datos relacionales guardan los índices, incluida la clave primaria, en árboles B: estructuras ordenadas divididas en páginas de tamaño fijo. Insertar un valor obliga a encontrar su lugar en el orden y escribirlo en la página correspondiente.

Con un autoincremental o un UUID v7, cada valor nuevo es mayor que el anterior, así que siempre se escribe en la última página del índice. Esa página está casi siempre en memoria, las páginas anteriores quedan completas y la escritura es secuencial.

Con un UUID v4, cada valor nuevo cae en una posición aleatoria. Eso tiene tres efectos que crecen con el tamaño de la tabla:

  • Más lecturas de disco: la página donde va el valor puede ser cualquiera, y con tablas grandes muchas no estarán en memoria.
  • Divisiones de página: cuando una página intermedia se llena, el motor la parte en dos, y las páginas quedan a medio llenar. El índice ocupa más espacio para la misma cantidad de datos.
  • Más escritura en el registro de transacciones: cada página modificada por primera vez después de un checkpoint puede escribirse completa en el WAL (en PostgreSQL, por ejemplo), y con inserciones aleatorias se modifican muchas más páginas distintas.

En tablas pequeñas la diferencia no se nota. En tablas de decenas de millones de filas con muchas inserciones, pasar de v4 a v7 suele reducir de forma visible el tamaño de los índices y el trabajo de escritura. Además, los v7 permiten ordenar por la clave primaria para obtener los registros en orden de creación, algo que con v4 no tiene sentido.

Lo que revela cada versión

Que el timestamp sea legible no es un detalle. Un UUID v7 revela cuándo se creó el registro con precisión de milisegundos. Si el identificador de un usuario aparece en una URL pública, cualquiera puede saber cuándo se registró; si los identificadores de pedidos son públicos, se puede estimar el ritmo de ventas comparando dos pedidos. Cuando esa información es sensible, hay dos salidas: usar v4 para los identificadores que se exponen, o usar v7 como clave interna y otro identificador para el exterior.

El caso histórico extremo es el UUID v1, que incluía la dirección MAC de la placa de red del equipo que lo generó. En 1999, los investigadores que rastrearon al autor del virus Melissa usaron, entre otras pistas, el identificador de ese tipo que Microsoft Word había incrustado en los documentos. Por eso v1 se considera hoy un formato heredado.

Un UUID v4 no revela nada, siempre que se genere con una fuente criptográfica. Aun así, el RFC 9562 aclara que no hay que tratar a ningún UUID como un secreto: para tokens de sesión, enlaces de restablecimiento o claves de API se usa un token aleatorio dedicado.

Colisiones: v4 y v7

Con 122 bits aleatorios, hacen falta unos 2,7 × 10¹⁸ UUID v4 para tener un 50 % de probabilidad de que al menos dos coincidan: mil millones por segundo durante 86 años. En un UUID v7, la parte aleatoria es de 74 bits, pero solo compite con los UUID generados en el mismo milisegundo. Aun generando un millón de UUID en un mismo milisegundo, la probabilidad de colisión es menor que 1 en 10¹⁰. Si además el generador usa el contador que permite el RFC, los UUID de un mismo proceso no pueden repetirse dentro del mismo milisegundo.

Comparación con otras alternativas

IdentificadorTamañoOrdenableGeneración descentralizadaRevela
Autoincremental4 u 8 bytesSíNoCantidad de registros y orden
UUID v416 bytesNoSíNada
UUID v716 bytesSíSíMomento de creación
ULID16 bytes (26 caracteres en texto)SíSíMomento de creación
Snowflake (Twitter/X)8 bytesSíSí, con un ID de máquina asignadoMomento y máquina de creación

ULID fue la respuesta de la comunidad al mismo problema antes de que existiera v7: 48 bits de timestamp y 80 aleatorios, escritos en Base32 de Crockford. Hoy v7 ofrece lo mismo con un formato estándar y compatible con el tipo uuid de las bases de datos. Los IDs tipo Snowflake ocupan la mitad (64 bits), pero exigen asignar un número a cada máquina generadora, lo que reintroduce algo de coordinación.

Generar cada versión en la práctica

Entornov4v7
Navegador y Node.jscrypto.randomUUID()Librería (por ejemplo, el paquete uuid)
Pythonuuid.uuid4()uuid.uuid7() desde Python 3.14
PostgreSQLgen_random_uuid()uuidv7() desde PostgreSQL 18
JavaUUID.randomUUID()Librería
Gouuid.New() (paquete google/uuid)uuid.NewV7() (mismo paquete)

Cuál elegir

  • Clave primaria de una tabla que crece mucho: v7. Mantiene los índices compactos y permite ordenar por creación.
  • Identificador que se muestra en URLs públicas y cuyo momento de creación es sensible: v4.
  • Identificador derivado de un nombre (el mismo correo siempre debe dar el mismo ID): v5.
  • Token de acceso, enlace de restablecimiento o clave de API: ninguno; un token aleatorio de al menos 128 bits generado específicamente para eso.
  • Sistema existente con v4: no hace falta migrar. Se puede empezar a generar v7 para las filas nuevas; las dos versiones conviven sin problema en la misma columna.

Resumen

Un UUID v4 son 122 bits de azar y no revela nada; un UUID v7 empieza con el timestamp en milisegundos y, por eso, queda ordenado por fecha de creación. Ese orden hace que v7 sea mucho mejor para los índices de las bases de datos, a cambio de exponer cuándo se creó cada registro. Para claves internas, v7; para identificadores públicos donde la fecha importa, v4; y para secretos, ninguno de los dos.

Herramientas usadas en esta guía

Guías relacionadas