
Tools used in this post
When you design a database or a distributed system, one of the earliest and most consequential decisions is how you generate identifiers. For decades the default was the auto-incrementing integer: 1, 2, 3, and so on. It is simple and compact, but it has two serious drawbacks in modern architectures. First, it leaks business intelligence — a competitor who signs up and gets user ID 48,201 learns roughly how many users you have. Second, it requires a central authority (the database) to hand out the next number, which becomes a bottleneck when many services need to create records at once.
UUIDs — Universally Unique Identifiers — solve both problems. They are 128-bit values designed to be globally unique without any central coordination, so any service on any machine can mint one independently with effectively zero chance of collision. But not all UUIDs are equal. For years, v4 was the default; today, v7 is often the better choice for database keys. Understanding why comes down to one word: ordering.
What is a UUID, exactly?
A UUID is a 128-bit number, conventionally written as a 32-character hexadecimal string in five hyphen-separated groups:
f47ac10b-58cc-4372-a567-0e02b2c3d479
Because the space of possible values is astronomically large (2^128), the probability of two independently generated UUIDs colliding is so small it is treated as impossible in practice. That property is what lets microservices, mobile clients, and background workers all generate primary keys simultaneously without checking a central registry first.
UUID v4: randomly generated
Version 4 is built almost entirely from randomness.
- Structure: of the 128 bits, 122 are purely random (the rest encode the version and variant).
- Example:
4a1b2c3d-8e9f-4123-a567-89abcdef0123 - Pros: trivial to generate anywhere; leaks nothing about when or where it was created, which is ideal for public-facing identifiers and one-time tokens.
- Cons: that randomness wrecks database write performance at scale. When you insert random values into a B-Tree index (used by MySQL, PostgreSQL, and most relational engines), each new key lands in an unpredictable spot. The index has to constantly split and rebalance pages, causing fragmentation, cache misses, and slow writes as the table grows.
UUID v7: time-ordered
Version 7, standardized in RFC 9562, was designed specifically to fix v4's index problem by putting time at the front of the value.
- Structure: the first 48 bits hold a Unix timestamp in milliseconds, followed by 74 bits of randomness.
- Example:
018c3f2d-7a1e-7123-b567-89abcdef0123 - Pros: because the leading bits increase with time, new keys are naturally close to the previous ones. Databases can append them sequentially to the end of the index — exactly the access pattern B-Trees love — preserving fast writes and eliminating fragmentation. They are also sortable by creation time for free.
- Cons: they reveal the approximate moment of creation, so they are a poor choice where you want to hide timing (a public URL that shouldn't disclose when a record was made).
Side-by-side comparison
| Feature | UUID v4 | UUID v7 |
|---|---|---|
| Generation strategy | 100% cryptographically random | Timestamp (48-bit) + randomness (74-bit) |
| Sortable by time? | No (random order) | Yes (monotonically time-ordered) |
| B-Tree index performance | Poor at scale (fragmentation) | Excellent (sequential appends) |
| Reveals creation time? | No | Yes (approximate) |
| Best used for | One-time tokens, session IDs, public URLs | Primary keys in SQL/NoSQL databases |
Why index performance matters more than it sounds
It is tempting to dismiss "index fragmentation" as an abstract concern, but the impact is concrete. As a table with random v4 primary keys grows into the millions of rows, insert throughput can degrade noticeably, index size in memory balloons, and the database spends more time shuffling pages than doing useful work. Teams that switch high-write tables from v4 to v7 frequently report meaningfully faster inserts and smaller indexes — with no application changes beyond the ID generator. If your UUIDs are primary keys, this is the difference that matters.
When to choose each — a practical rule
- Use v7 for database primary keys, especially on high-write tables, and anywhere you benefit from time-ordering (event logs, append-heavy tables).
- Use v4 for public-facing identifiers, password-reset tokens, session IDs, and API keys — anything where you specifically do not want to leak timing information.
Many systems use both: v7 internally for primary keys, v4 externally for tokens and public URLs.
Validation and generation in practice
Whether you are seeding a test database, generating keys for a new feature, or auditing IDs coming from a third party, two operations come up constantly: generating clean UUIDs in bulk, and validating that a given string is a well-formed UUID of a specific version. A validator confirms format, version, and RFC compliance — useful when you are debugging why a "UUID" from an upstream system is being rejected. And when you need secret keys or credentials rather than identifiers, a dedicated secure password generator is the right tool, since it is built for unpredictability rather than uniqueness.
Generate UUIDs for your applications
All of the tools below generate values locally in your browser using the secure Web Crypto API — nothing is logged or sent to a server.
Generate and Validate UUIDs Instantly
Fast, browser-side developer tools for seeding, testing, and API work:
- 🆔 Bulk UUID Generator: Generate hundreds of secure UUID v4 and time-ordered v7 strings in seconds.
- ✅ UUID Validator: Check format, verify the version (v1, v4, v7), and confirm RFC compliance.
- 🔐 Secure Password Generator: Generate unhackable random secret keys and credentials.
🔒 100% client-side generation: all UUIDs are generated inside your browser using secure Web Crypto APIs. Nothing is logged or saved to external servers.
UUIDs vs auto-increment integers vs ULIDs
UUIDs are not the only identifier strategy, and choosing well means knowing the alternatives:
- Auto-increment integers are compact and fast but leak volume (competitors can guess your growth), require a central authority to issue, and complicate merging data across shards or databases.
- UUID v4 removes those problems but hurts index performance and takes 16 bytes.
- UUID v7 keeps the decentralization while restoring index-friendly ordering — the best of both for most databases.
- ULIDs are a non-standard cousin of v7: also time-ordered, but encoded in a shorter, URL-friendly Base32 string. They predate v7 and solve the same problem; if you are starting fresh, standard v7 is usually the better bet because it is an official RFC.
For greenfield projects, the modern default is v7 primary keys internally and v4 tokens externally.
Storing UUIDs efficiently
A common performance mistake is storing UUIDs as text. A UUID is 128 bits — 16 bytes — but written as a hyphenated hex string it takes 36 characters. Storing it as a CHAR(36) roughly doubles the storage and slows comparisons versus a native binary type. PostgreSQL has a dedicated uuid type; MySQL can store them as BINARY(16). Using the native or binary representation keeps indexes compact and joins fast. This matters most on the very high-write tables where you chose v7 for performance in the first place — do not undo the win by storing the key inefficiently.
Testing and seeding with UUIDs
Beyond production keys, UUIDs are invaluable in development. Seeding a test database with realistic, unique keys, generating fixture data, load-testing an API with thousands of distinct IDs, or reproducing a bug that only appears with specific key patterns all call for generating UUIDs in bulk. Because generation is instant and collision-free, you can create hundreds at once without coordination. Pair that with a validator when you are debugging IDs coming from an external system, and you have a complete UUID workflow — generate what you need, verify what you receive.
Key takeaways
- UUIDs give globally unique IDs with no central authority, unlike auto-increment integers.
- v4 is fully random — great for tokens and public IDs, poor for database index performance.
- v7 puts a timestamp first, so it inserts sequentially and keeps B-Tree indexes fast.
- Use v7 for primary keys, v4 for tokens and public URLs; many systems use both.
- Store UUIDs in a native or binary column, not as text, to keep indexes compact.
Frequently asked questions
Should I replace UUID v4 with UUID v7 for database primary keys?
Yes, in most cases. If you use UUIDs as primary keys in PostgreSQL, MySQL, or MongoDB, switching to v7 dramatically improves write throughput and cuts index memory use, thanks to sequential insertion.
Can two UUID v7 keys collide in the same millisecond?
Practically never. Within a single millisecond, v7 still uses 74 bits of entropy plus sub-millisecond ordering, making collisions vanishingly unlikely even at high generation rates.
Are UUIDs a security feature?
Not by themselves. A random v4 is hard to guess, which is useful for tokens, but UUIDs are identifiers, not secrets. Never rely on an "unguessable" UUID in a URL as your only access control.
Is v7 supported in my language or database?
Support has expanded rapidly since RFC 9562. Many languages, ORMs, and databases now offer native v7 generation, and where they do not, small libraries fill the gap. Generating v7 client-side and inserting it as a normal UUID column always works.


