{"post":{"slug":"uuid-v7-explained-2026","title":"UUID v7: Opaque Identifiers That Insert Sequentially","excerpt":"Random UUIDs fragment your storage. Version 7 puts a timestamp in the high bits, so identifiers sort roughly by creation time and insert cleanly at the end.","category":"code","date":"January 1, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">R</span>andom UUIDs solved the problem of generating unique identifiers without coordination, and created a database problem: they insert at random positions, which fragments index and table storage on any system that stores rows in key order.\n\nVersion 7 addresses that directly by putting a millisecond timestamp in the high-order bits, followed by randomness. The result is still a UUID, still generatable anywhere, and now roughly sortable by creation time.\n\n## What changed in 2026\n\n- **Native database support spread.** More engines gained built-in generation functions, removing the need for application-side libraries.\n- **It became the recommended default.** Where a UUID is needed, v7 largely displaced v4 in new designs.\n- **Library support matured.** Generation became available across mainstream languages without third-party dependencies in many cases.\n- **The timestamp exposure got discussed.** Awareness that creation time is inferable became part of the decision rather than a surprise.\n\n## Why sortability fixes the problem\n\nDatabases that store rows in primary key order — or maintain a B-tree index on it, which is nearly all of them — care where a new key lands.\n\nA random key lands anywhere. The target page is usually full, so it splits into two half-full pages. Sustained random insertion produces a structure of half-empty pages: more storage, more pages read per scan, and worse cache utilisation because the same data occupies more space.\n\nA key that increases monotonically always lands at the end. Pages fill completely before a new one is created. No splits, compact storage.\n\nVersion 7's timestamp prefix means identifiers generated later sort after identifiers generated earlier, so inserts append. The randomness in the lower bits provides uniqueness within the same millisecond and across generators.\n\n| | v4 (random) | v7 (time-ordered) |\n| --- | --- | --- |\n| Insert position | Random | Appends |\n| Page splits | Frequent | Rare |\n| Storage compactness | Poor | Good |\n| Sortable by creation | No | Yes, approximately |\n| Reveals creation time | No | Yes |\n| Uniqueness guarantee | Random | Random within a millisecond |\n\n## What it reveals\n\nThe tradeoff, and it is not hidden: **the creation timestamp is recoverable from the identifier.**\n\nFor most applications that is irrelevant or mildly useful — being able to sort records by identifier and get creation order is convenient.\n\nWhere it matters: if the existence and timing of a record is sensitive, publishing an identifier that encodes when it was created discloses that. A record identifier revealing that an account was created at a particular moment may be more than you intended.\n\nIt also enables limited inference about volume. Two identifiers created close in time have similar prefixes, so an observer can tell whether records were created together — less informative than sequential integers, and not nothing.\n\nIf time must not be inferable, use a fully random version and accept the insert cost, or use an internal integer key with a random external identifier per [UUID vs bigint keys](/blog/uuid-vs-bigint-keys-2026).\n\n## Practical notes\n\n**Store it as a native UUID type**, not as text. Text storage roughly doubles the size again and loses type checking. This is a common and entirely avoidable mistake.\n\n**Sort order is approximate.** Identifiers generated within the same millisecond, or by clocks that are slightly out of sync, may not order strictly by true creation time. Do not use identifier order as an authoritative event sequence — use a timestamp column for that.\n\n**Clock behaviour matters.** A generator whose clock moves backwards produces identifiers that sort before earlier ones. Rare, and worth knowing if you rely on ordering.\n\n**Uniqueness is still probabilistic.** Extremely unlikely to collide, and not impossible, so keep the unique constraint.\n\n## Common mistakes\n\n- **Storing as text.** Doubles the size, loses type safety.\n- **Treating identifier order as authoritative event order.** It is approximate.\n- **Using v7 where creation time must stay private.** It is recoverable.\n- **Assuming it removes the storage overhead.** Still 16 bytes.\n- **Dropping the unique constraint.** Probabilistic uniqueness is not a guarantee.\n- **Mixing versions in one column.** Sort order becomes meaningless.\n\n## FAQ\n\n**Is this the same as ULID?**\nThe idea is the same — a timestamp prefix with randomness. Version 7 is the standardised UUID form, which means native database and library support and compatibility with anything expecting a UUID.\n\n**Should I migrate existing v4 identifiers?**\nGenerally not. Migrating primary keys is expensive, and mixed versions in one column defeat the sortability benefit. Use v7 for new tables.\n\n**Does it help on databases that do not cluster by primary key?**\nLess, since rows are not stored in key order. The primary key *index* still benefits from sequential insertion, so there is a real if smaller gain.\n\n**What about the index still being 16 bytes?**\nUnchanged. Version 7 fixes insert behaviour, not size. If size is your concern, an integer key is the answer.\n\n## Where to go next\n\nFor the broader key-type decision, read [UUID vs bigint keys](/blog/uuid-vs-bigint-keys-2026). For why insert order matters, [clustered indexes](/blog/clustered-indexes-explained-2026), and for the fragmentation it prevents, [index bloat](/blog/index-bloat-explained-2026).","hue":304,"metaTitle":"UUID v7: Opaque Identifiers That Insert Sequentially","metaDescription":"How UUID version 7 combines a timestamp prefix with randomness to give sortable identifiers, why it fixes insert fragmentation, and what it reveals.","keywords":["uuid v7","time ordered uuid","sortable identifiers","uuid insert performance","distributed id generation","ulid comparison","primary key design","database identifiers 2026"],"tldr":["**A timestamp prefix makes them sort by creation time** — so inserts append rather than scattering.","**It removes the fragmentation cost of random UUIDs** — the main objection to UUID keys.","**Creation time is inferable from the identifier** — by design, and worth knowing if that is sensitive.","**They are still 16 bytes** — the storage overhead against an integer remains.","**Skip:** v7 where you need identifiers with no time information at all. Use a random version there."],"readTime":"4 min read","wordCount":849},"related":[{"slug":"uuid-vs-bigint-keys-2026","title":"UUID vs Bigint Keys: The Tradeoff Nobody Measures","excerpt":"Sequential integers are compact and reveal your row counts. UUIDs are opaque and generatable anywhere, and they cost more in storage, index size, and insert performance.","category":"code","date":"February 3, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":313},{"slug":"idempotency-explained-2026","title":"Idempotency explained in 2026: keys, retries, and safe API design","excerpt":"Idempotency is the property that makes retries safe. This 2026 guide explains idempotency keys, when operations are naturally idempotent, and how to build APIs that survive network failures without double-charging users.","category":"code","date":"March 2, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":315},{"slug":"clustered-indexes-explained-2026","title":"Clustered Indexes: When Physical Order Matters","excerpt":"Storing rows in index order makes range scans dramatically faster and makes the choice of key a decision you live with, because inserting in the wrong order fragments everything.","category":"code","date":"January 8, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":317}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"utility-setup-checklist-2026","title":"Utility Setup: Getting Services Running Before You Move In","excerpt":"Arriving at a new home with no power, no water, and no internet is avoidable. Most of it requires a phone call weeks in advance, and the lead times differ enormously.","category":"guides","date":"January 1, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":144},"older":{"slug":"vocabulary-size-explained-2026","title":"Vocabulary Size: Trading Memory for Token Efficiency","excerpt":"A larger vocabulary means fewer tokens per document and a much larger embedding layer. The tradeoff has moved as models and context windows have grown.","category":"ai","date":"January 1, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":198}}