Desarrollo

UUID v4 vs v7: cuál usar, y qué te cuesta el v7

v7 para claves de base de datos, v4 cuando la hora de creación no es asunto de nadie más. Los bits detrás de esa regla, y los dos lugares donde v7 no hace nada.

Usa v7 cuando el UUID vaya a ser la clave primaria de una base de datos. Usa v4 cuando el identificador lo vayan a ver personas que no tienen por qué saber cuándo se creó la fila. Esa es toda la decisión, y se reduce a una diferencia estructural: un UUID v7 empieza con un timestamp Unix de 48 bits en milisegundos, así que los valores generados después quedan ordenados detrás de los generados antes. Un UUID v4 son 122 bits aleatorios y nada más, así que no queda en ningún orden en particular y no revela absolutamente nada.

¿Qué cambia realmente en los bits?

Los dos son de 128 bits, escritos como 32 dígitos hexadecimales en el patrón 8-4-4-4-12 que suma 36 caracteres con los guiones. Los dos gastan 4 bits en un nibble de versión y 2 en un marcador de variante. El resto es donde se separan.

v4v7
Estructura122 bits aleatoriosreloj de milisegundos de 48 bits, después 74 bits aleatorios
Queda en orden de creaciónNoSí, entre milisegundos distintos
Revela cuándo se creóNoSí, al milisegundo
AdivinableNoNo
Úsalo cuandoEl valor es público y la hora noEl valor es una clave primaria

La versión vive en el decimotercer dígito hexadecimal, el que va justo después del segundo guion: un 4 o un 7. Si tienes un identificador delante y ni idea de cuál de los dos es, el inspector del generador de UUID lee ese nibble y, si es un v7, decodifica los primeros bytes de vuelta a una fecha y una hora.

Ese valor inicial es una cuenta común de milisegundos desde el 1 de enero de 1970 UTC — el mismo número que guarda un timestamp Unix, almacenado como hexadecimal big-endian en lugar de escrito en decimal. Ahí no pasa nada ingenioso. Es la lectura de un reloj pegada al frente de un número aleatorio.

¿Por qué v7 indexa mejor?

Las bases de datos guardan las claves primarias en un árbol B ordenado. Una clave v4 cae en un punto aleatorio de ese árbol. En una tabla chica eso no cuesta nada, porque el índice entero está en memoria. En una grande, la base de datos trae del disco la página de destino, y cuando esa página está llena la divide en dos, dejando las dos a medio llenar. Unos millones de inserciones después, el índice es más grande de lo que necesita ser, queda medio vacío y se lo relee del almacenamiento todo el tiempo.

Una clave v7 se agrega al final. Cada valor es mayor que los generados en milisegundos anteriores, así que las inserciones caen en la página más a la derecha del árbol — la que ya está en memoria porque acabas de escribir en ella. Las páginas se llenan del todo en lugar de partirse por la mitad, y el conjunto de páginas que se tocan sigue siendo chico por más que crezca la tabla.

La salvedad honesta: esto solo empieza a importar cuando el índice deja de entrar en la RAM. En una tabla chica no vas a medir nada, y quien cite una mejora espectacular sin decir cuántas filas tenía ni con qué hardware está citando un benchmark construido para producirla. La razón para usar v7 por defecto igual es que la tabla que vas a tener dentro de tres años es la que sí va a notarlo, y cambiar el tipo de una clave primaria después es genuinamente doloroso.

¿Qué revela un UUID v7?

El timestamp no está cifrado ni ofuscado. Cualquiera que tenga un UUID v7 puede leer el milisegundo en que se hizo, y cualquiera que tenga dos puede leer el intervalo entre ellos. Si el identificador aparece en una URL, en una factura o en una respuesta de API, acabas de publicar eso.

A veces es inofensivo. A veces es un competidor contando tus IDs de pedido durante una semana para estimar tu ritmo de ventas, o un usuario descubriendo que una cuenta marcada como "miembro desde 2019" se creó el martes pasado. Decide en cuál de los dos casos estás antes de poner un v7 en un campo público.

Lo que v7 no hace es volver adivinables los identificadores. Los 74 bits aleatorios que quedan son demasiados para enumerarlos, así que nadie va a recorrer tu base de datos incrementando un UUID. La fuga es el timestamp, no la secuencia.

Ninguna de las dos versiones es un secreto. Los UUID se tratan como identificadores en todo lo que viene después, así que terminan en logs de servidor, en eventos de analítica, en cabeceras Referer y en capturas pegadas en un chat. Si necesitas un token de recuperación de contraseña o un enlace para compartir imposible de adivinar, usa un generador de contraseñas pensado para secretos y guarda un hash de él, en lugar de reutilizar un ID que la mitad de tu stack está escribiendo en disco en texto plano.

¿Dónde no ayuda v7?

SQL Server, si usas el tipo nativo

El uniqueidentifier de SQL Server no compara los bytes de izquierda a derecha. Trata los últimos seis bytes como los más significativos y después va hacia atrás por los grupos anteriores. Un UUID v7 pone su timestamp en los primeros seis bytes — exactamente los que SQL Server mira al final. Así que los valores v7 se dispersan por un índice clustered casi tan mal como los v4, y el beneficio se evapora. Guardarlos como binary(16), o usar un GUID estilo COMB que ponga la parte creciente al final, es la solución habitual.

Dentro de un mismo milisegundo

Dos UUID v7 hechos en el mismo milisegundo tienen timestamps idénticos, así que su orden relativo lo deciden los bits aleatorios — es decir, es arbitrario. El RFC 9562 permite gastar parte del campo aleatorio en monotonía, sea con un contador o con precisión extra de reloj, y algunas implementaciones lo hacen: el uuidv7() integrado de PostgreSQL pone precisión de reloj por debajo del milisegundo en esos bits. El generador de aquí no; los llena de aleatoriedad, lo cual cumple el estándar pero significa que un lote de mil hechos en un milisegundo no tiene orden interno. Entre milisegundos distintos el orden es exacto. Si dependes del orden de los UUID como criterio de desempate en una ruta de escritura intensa, revisa qué hace realmente tu biblioteca.

Y el orden de v7 es solo tan bueno como los relojes que lo producen. Dos servidores separados por cien milisegundos intercalan sus IDs, y un reloj que se atrasa de golpe produce valores que quedan ordenados antes que otros escritos previamente. Alcanza para la localidad del índice, no es una fuente de verdad sobre la secuencia.

¿Sigue siendo v4 un valor por defecto razonable?

Sí, para todo lo que no sea una clave primaria de alto volumen. Viene siendo la opción sensata desde hace veinte años y no dejó de funcionar. Las colisiones no son la preocupación en ninguna de las dos versiones. La cota del cumpleaños sitúa una probabilidad del 50% de una sola colisión v4 en unos 2,7 trillones de identificadores; para v7, donde solo pueden chocar valores que comparten milisegundo, hacen falta unos 160 mil millones dentro de ese mismo milisegundo.

Lo que sí sale mal es una fuente de aleatoriedad débil. El código viejo a menudo armaba los UUID a mano con Math.random, que es rápido, no es criptográfico y nunca se pensó para esto. El resultado pasa cualquier validador, porque el nibble de versión sigue diciendo 4 y los bits se ven como los de cualquier otro UUID desde afuera. Ningún inspector puede detectarlo — tampoco el de este sitio, porque lee bits y no tiene nada más de donde agarrarse. La única forma de saberlo es abrir el código y ver si llama a la API criptográfica de la plataforma.

¿Y ULID, v1 y v6?

ULID es anterior a v7 y resuelve el mismo problema: 48 bits de timestamp en milisegundos más 80 bits aleatorios, escritos como 26 caracteres de base32 de Crockford en lugar de hexadecimal. Es más corto y no distingue mayúsculas de minúsculas, pero no es un UUID, así que los tipos de base de datos, los validadores y los ORM no lo reconocen sin ayuda. v7 es la versión estandarizada de la misma idea.

v1 es el UUID original basado en tiempo: el reloj está partido en tres trozos en el orden equivocado para ordenar, y los últimos seis bytes son un identificador de nodo que históricamente era la dirección MAC de la máquina. v6 es v1 con esos campos reordenados para que ordenen, y existe sobre todo para que los sistemas que ya tienen valores v1 puedan migrar. v3 y v5 son otra herramienta distinta — pasan un namespace y un nombre por una función hash, así que la misma entrada produce siempre el mismo UUID. Ninguno de ellos es la respuesta correcta para trabajo nuevo que necesite valores únicos frescos.

¿Cómo conviene guardar un UUID?

Como 16 bytes, no como 36 caracteres. Una columna CHAR(36) guarda los guiones y la escritura hexadecimal en lugar del valor en sí, y cada índice construido sobre ella carga con el mismo peso muerto — lo que deshace buena parte de aquello por lo que cambiaste a v7.

PostgreSQL tiene un tipo uuid nativo. La versión 18, publicada en septiembre de 2025, agregó un uuidv7() integrado; uuid_extract_timestamp() llegó antes, en la versión 17, y ahora lee valores v7 además de v1. MySQL no tiene ningún tipo UUID, así que BINARY(16) con UUID_TO_BIN en los bordes es el arreglo habitual. Deja apagado el flag de intercambio de esa función para v7: intercambia el primer y el tercer grupo de dígitos hexadecimales, que es lo que un UUID v1 necesita para ordenar y exactamente lo que arruina a uno v7. El propio manual de MySQL dice que el intercambio solo beneficia a los valores de versión 1.

Normaliza la forma de texto a minúsculas y con guiones antes de que llegue a la base de datos, sea cual sea el tipo que elijas. Esa es la representación canónica, y una tabla que guarda las dos escrituras del mismo identificador es una cacería de bugs que nadie disfruta.

Si lo que necesitas son identificadores y no una decisión, el generador de UUID hace los dos tipos de a mil por vez y también desarma uno existente para decirte de qué versión es y, si es un v7, cuándo se hizo. Corre entero en tu navegador y toma su aleatoriedad del generador criptográfico de la plataforma, no de Math.random.

Algo que la gente intenta después es encoger la forma de texto de 36 caracteres codificando los 16 bytes crudos, lo que la baja a 22 caracteres. Qué es Base64 y cuándo lo necesitas de verdad cubre qué le hace esa codificación a tus datos y por qué existe la variante segura para URL — vale la pena leerlo antes de poner la forma corta en una ruta.

Preguntas frecuentes

¿Debería usar UUID v4 o v7?

Usa v7 para claves primarias de base de datos y para cualquier otra cosa que se indexe a gran escala, porque su timestamp inicial hace que las inserciones se agreguen al final del índice en lugar de dispersarse por él. Usa v4 cuando el identificador es público y la hora de creación debe quedar en privado. Para IDs internos de bajo volumen, cualquiera de los dos sirve.

¿Es seguro exponer un UUID v7 en una URL?

No se puede adivinar, pero no es privado. Los primeros 48 bits son la hora de creación en milisegundos, legible por cualquiera que tenga el valor, así que un ID v7 público publica cuándo se creó el registro. Los 74 bits aleatorios restantes hacen que nadie pueda enumerar tus registros, así que la única fuga real es el timestamp.

¿Los UUID v7 colisionan más que los v4?

En el papel sí, en la práctica no. Un UUID v4 tiene 122 bits aleatorios contra los 74 de v7, pero dos valores v7 solo pueden colisionar si se generaron en el mismo milisegundo, y llegar a una probabilidad del 50% de eso exige unos 160 mil millones dentro de ese único milisegundo. Con cualquiera de las dos versiones el riesgo realista es una fuente de aleatoriedad débil, no la cantidad de bits.

¿Funciona UUID v7 en SQL Server?

Se genera y se guarda sin problema, pero el beneficio de rendimiento no sobrevive al tipo nativo uniqueidentifier. SQL Server compara esos valores empezando por los últimos seis bytes, y v7 pone su timestamp en los primeros seis, así que los valores siguen cayendo de forma aleatoria en un índice clustered. Guárdalos como binary(16) o usa un esquema de GUID secuencial diseñado para SQL Server.

¿Cuál es la diferencia entre UUID v7 y ULID?

Codifican la misma idea: un timestamp de 48 bits en milisegundos seguido de bits aleatorios. ULID usa 80 bits aleatorios y una forma de texto de 26 caracteres en base32, mientras que v7 usa 74 bits aleatorios y la forma UUID estándar de 36 caracteres. v7 es parte del RFC 9562, así que bases de datos, validadores y bibliotecas lo reconocen de forma nativa; ULID suele necesitar tratamiento extra.

¿Cómo sé qué versión de UUID tengo?

Mira el decimotercer dígito hexadecimal, que es el primer carácter después del segundo guion. Ahí va el número de versión, así que un 4 significa un v4 aleatorio y un 7 significa un v7 ordenado por tiempo. El carácter que sigue al tercer guion es la variante, y por eso tantos UUID tienen un 8, un 9, una a o una b en ese lugar.

Última actualización 19 de septiembre de 2026