flashman
← All guides

Choose UUID v7 when time order matters

Use UUID version 7 when insertion order should follow creation time, and keep version 4 when the identifier must not reveal when it was minted.

2026-10-14 · 8 min read

  • uuid
  • identifiers
  • databases

UUID version 4 is 122 bits of randomness with a version nibble and variant bits. It is a good opaque identifier. It is a poor clustering key, and sorting it does not mean sorting by creation time.

UUID version 7, from RFC 9562, stores a 48-bit Unix millisecond timestamp in the high bits and uses the remaining bits for randomness and the required version and variant. Databases that insert in id order then append new rows instead of scattering them.

Pick the version for the property you need

Choose version 7 for primary keys where recent rows should sit together in the index and where revealing a rough creation time is acceptable. Choose version 4 for tokens, unguessable links, and any id that must not advertise when it was minted.

Do not switch a live column from one version to the other without a plan for readers. Both fit in a uuid column. Application code that assumes every id is random, or that string order is meaningless, will change behavior on the first version 7 value.

  • Document the version next to the column.
  • Generate version 7 in one shared library.
  • Keep version 4 for secrets and capability URLs.
  • Do not parse the timestamp in authorization checks.

Know what the timestamp does and does not order

The timestamp is milliseconds. Two ids from the same millisecond on different machines are ordered by their random bits, not by a global sequence. A clock step backward can place a new id before an older one. Version 7 is not a replacement for a transaction sequence or for an ORDER BY created_at that you already store.

The canonical text form sorts in the same rough order as the bytes, because the timestamp is the leftmost hex. That stops being true if some writers omit hyphens, change case, or wrap the id in a prefix.

Store one representation

Prefer a native uuid type when the database has one. If you store text, write the lowercase canonical form and reject anything else at the boundary. Mixing formats creates a sort that looks like a time-order bug and is actually a formatting bug.

Indexes on random version 4 keys fragment as the table grows. Version 7 reduces that for insert-heavy tables. It does not make an unindexed lookup faster, and it does not hide the creation time from anyone who can see the id.

Test the writers you will actually run

Generate a version 4 fixture, a version 7 fixture from the shared library, and a version 7 fixture from a second language in the same system. Strip hyphens, confirm the version character, and convert the first twelve hex digits to a millisecond timestamp. The two version 7 clocks should agree within the skew you allow.

Include a same-millisecond pair and a clock-step case in the notes. The product owner should see that those pairs are not a total order before they ask for a gapless export.

Inspect ids locally

Flashman's UUID tool generates version 4 values for the random case. Use the timestamp converter on the version 7 millisecond prefix, diff to compare canonical and stripped forms, and the JSON formatter when the id arrives inside an API body.

Record the version, the stored form, and the column type in the migration notes. The next reader should not have to rediscover which sort the index is performing.

Try these tools