UUIDv7 timestamps are not what you think
UUIDv7 is usually sold with three promises: IDs that always increase, a timestamp that tells you when the row was created, and IDs nobody can guess. In a post from 19 October 2026, Robert Alexander argues that only one property is strictly held, uniqueness, and that the spec itself allows the rest to bend. If you use HasUuids in Laravel, you are using UUIDv7, so it is worth knowing which of those promises your code is leaning on.
The spec lets the timestamp drift
RFC 9562 says implementations "MAY alter the actual timestamp", makes no guarantee about how close the clock value is to real time, and allows incrementing it ahead of the actual time. Postgres says the same in its docs for uuid_extract_timestamp: the extracted value is not necessarily the moment the UUID was generated.
The reason is a trade-off between keeping IDs in order and keeping the time accurate. When the clock goes backwards, a generator that refuses to go back in time has to keep using a timestamp that is now in the future.
Python shows how far it can go
Alexander's example uses Python 3.14's uuid.uuid7(). He sets the clock back one hour while the script generates IDs in a loop. You would expect the gap between the embedded timestamp and the clock to be 3,600 seconds and then shrink. At more than one ID per millisecond it grows instead: his run printed about 3,695, then 3,795, 3,894 and 3,994 seconds. The related Python issue treats this as consistent with the RFC and with other implementations, and he says he sees the same behaviour elsewhere.
What Laravel's generator does
I read the code that ships in this site's vendor/ folder rather than guess. HasUuids creates keys with Str::uuid7(), which calls ramsey/uuid. Its UnixTimeGenerator takes the time in milliseconds and keeps the last time it used in a static property. If the new time is later, it picks fresh random bits. If not, either the same millisecond or a clock that went back, it keeps the last time and increments the random part. If that increment overflows, it moves the stored time forward by one millisecond.
What that means in practice, from the code alone: within one PHP process the timestamp never goes backwards, and after a clock step back new IDs carry the older, later-looking time until the clock catches up. The last time lives in memory, not on disk, so a new process starts fresh, and two servers know nothing about each other's clocks. Nothing in it promises order across processes or machines.
Two smaller caveats
The timestamp leaks. You cannot share a UUIDv7 without sharing when it was made, to the millisecond. Alexander rates this low for most apps, but a profile URL that reveals the account's sign-up time is one example where it matters.
The order is rough. Clocks on different machines cannot be synced to millisecond precision, and an implementation without a counter can produce out-of-order IDs inside one loop. Rough order is still useful for index locality. It is not a sequence.
What to rely on in a Laravel app
Rely on uniqueness, and on rough insert order being good for the index. Do not parse the ID to find when a row was created: keep created_at, and sort by it when the order matters to a person. Do not use the ID as proof of which event happened first across servers. And if the creation time is private, do not put a UUIDv7 in a public URL. If you want to look at the structure of one, the UUID generator on this site makes v7 IDs in your browser.
created_at as the record of when.Next step: search your code for anything that reads the time out of a UUID or orders by the ID where a person expects time order, and switch it to created_at. Source: Robert Alexander, UUIDv7 doesn't have the properties you think it does.
Notes from readers