Todos los artículos

La marca de tiempo de UUIDv7 no es lo que crees

Bases de datos · 4 min de lectura ·

UUIDv7 suele venderse con tres promesas: identificadores que siempre crecen, una marca de tiempo que dice cuándo se creó la fila e identificadores que nadie puede adivinar. En un artículo del 19 de octubre de 2026, Robert Alexander sostiene que solo una propiedad se cumple de verdad, la unicidad, y que la propia especificación permite doblar el resto. Si usas HasUuids en Laravel, estás usando UUIDv7, así que conviene saber en cuál de esas promesas se apoya tu código.

La especificación deja que la marca de tiempo se desvíe

La RFC 9562 dice que las implementaciones pueden alterar la marca de tiempo real, no garantiza lo cerca que esté el valor del reloj de la hora real y permite incrementarla por delante de la hora efectiva. La documentación de Postgres para uuid_extract_timestamp dice lo mismo: el valor extraído no es necesariamente el momento en que se generó el UUID.

El motivo es un equilibrio entre mantener los identificadores en orden y mantener la hora exacta. Cuando el reloj retrocede, un generador que se niega a volver atrás tiene que seguir con una marca de tiempo que ahora está en el futuro.

pasa el tiempo real el reloj retrocede marca del ID por delante
El orden se mantiene congelando la marca de tiempo. Mientras está congelada, no es la hora de creación.

Python muestra hasta dónde puede llegar

El ejemplo de Alexander usa uuid.uuid7() de Python 3.14. Retrasa el reloj una hora mientras el script genera identificadores en un bucle. Lo esperable sería una diferencia de 3600 segundos entre la marca incrustada y el reloj, que luego se reduce. Con más de un identificador por milisegundo crece en cambio: su ejecución imprimió unos 3695, luego 3795, 3894 y 3994 segundos. La incidencia de Python relacionada lo considera coherente con la RFC y con otras implementaciones, y él dice ver el mismo comportamiento en otras.

Qué hace el generador de Laravel

Leí el código que viene en la carpeta vendor/ de este sitio en lugar de suponer. HasUuids crea las claves con Str::uuid7(), que llama a ramsey/uuid. Su UnixTimeGenerator toma la hora en milisegundos y guarda la última hora usada en una propiedad estática. Si la hora nueva es posterior, elige bits aleatorios nuevos. Si no, sea el mismo milisegundo o un reloj que retrocedió, conserva la última hora e incrementa la parte aleatoria. Si ese incremento se desborda, adelanta la hora guardada un milisegundo.

En la práctica, solo a partir del código: dentro de un proceso PHP la marca de tiempo nunca retrocede, y después de un retroceso del reloj los nuevos identificadores llevan la hora anterior, que parece posterior, hasta que el reloj la alcanza. Esa última hora vive en memoria, no en disco, así que un proceso nuevo empieza de cero, y dos servidores no saben nada del reloj del otro. Nada ahí promete orden entre procesos ni entre máquinas.

Dos advertencias menores

La marca de tiempo se filtra. No puedes compartir un UUIDv7 sin compartir cuándo se creó, al milisegundo. Alexander lo considera poco grave para la mayoría de las aplicaciones, pero una URL de perfil que revela cuándo se registró la cuenta es un caso en el que importa.

El orden es aproximado. Los relojes de máquinas distintas no se sincronizan al milisegundo, y una implementación sin contador puede producir identificadores desordenados dentro de un solo bucle. El orden aproximado sigue siendo útil para la localidad del índice. No es una secuencia.

tiempo (6 bytes, ms) versión + aleatorio lo lee quien tenga el ID columna created_at el registro real
El identificador es para identificar. La hora va en una columna que controlas tú.

En qué confiar en una app Laravel

Confía en la unicidad y en que el orden aproximado de inserción le viene bien al índice. No analices el identificador para saber cuándo se creó una fila: conserva created_at y ordena por ella cuando el orden le importa a una persona. No uses el identificador como prueba de qué evento ocurrió primero entre servidores. Y si la hora de creación es privada, no pongas un UUIDv7 en una URL pública. Si quieres ver cómo está hecho uno, el generador de UUID de este sitio crea identificadores v7 en tu navegador.

UUIDv7 garantiza un identificador único. La marca de tiempo que lleva dentro es una pista que el generador puede doblar, así que conserva created_at como registro de cuándo.

Siguiente paso: busca en tu código lo que lee la hora de un UUID o lo que ordena por identificador donde una persona espera orden cronológico, y cámbialo a created_at. Fuente: Robert Alexander, UUIDv7 doesn't have the properties you think it does.

Notas de los lectores

  1. Todavía no hay notas. La primera siempre es la más valiente.
¿Estás construyendo algo parecido? Puedo ayudarte. Escríbeme por WhatsApp