Choose v4 when
The identifier appears in public URLs, behaves like a secret token, or belongs to data where ordering is meaningless. If unpredictability is itself the requirement, v4 is correct and there is no reason to change.
브라우저 내부 처리
Plenty of articles stop at "v7 is better". This one looks at how the bits differ, what that changes inside a database, and what v7 gives up in return.
The identifier appears in public URLs, behaves like a secret token, or belongs to data where ordering is meaningless. If unpredictability is itself the requirement, v4 is correct and there is no reason to change.
It is the primary key of a large, append-heavy table, an event log, or queue records — workloads where insert order and sort order being the same is what pays off.
If the table holds a few hundred thousand rows, the primary key is not a UUID, or inserts are rare, switching from v4 to v7 changes little you can measure. The benefit comes from scale.
The reasoning follows. To compare actual values, switch between v4, v7 and ULID in the generation mode of the UUID converter.
Both are 128 bits and share the same string form. What differs is what fills those bits. Standardised in RFC 9562, v7 hands the leading bits over to time.
Excluding four version bits and two variant bits, 122 bits are random. Collisions are not a practical concern, and the value reveals nothing about when it was created. The 4 at the 14th character of the string is the version marker.
Unix epoch milliseconds come first, then four version bits (0111, so a 7 at the 14th character), two variant bits, and 74 random bits. Because time leads, sorting the strings lexicographically sorts them by creation order. That is the whole idea.
01a013ab-09ca-7958-88e4-7f9866134ad6 and 01a013ab-09d0-7ec6-ac2e-079d51b83123 are two v7 values generated moments apart. The first eight characters match and the next segment ticks up. Two v4 values differ from the very first character.
The timestamp is identical, so the remaining 74 random bits decide. Order within a single millisecond is not guaranteed. If you need strict monotonicity, choose an implementation using the counter method the RFC permits; millisecond-level ordering is enough for most applications.
"v4 is bad for indexes" is repeated often but rarely explained. Looking at how a B-tree works reduces it to a single cause.
A B-tree stores values in sorted pages. Sequential keys always append to the rightmost page, so a full page simply gets a new sibling. Random keys land in the middle of already-full pages, which forces repeated page splits. Split pages stay half empty, inflating the index and increasing disk reads.
With sequential keys the page you just wrote is still in memory, so the next insert reuses it. Random keys touch a different page every time, pulling pages in from disk. The gap widens sharply once the table outgrows memory.
In InnoDB the primary key is the clustered index, so primary key order is the physical row order. A random primary key scatters the rows themselves. Every secondary index also stores the primary key, so a large key inflates all of them.
The important part is that all of this is a question of scale. While the table fits in memory, neither page splits nor cache misses are noticeable. Reports of a visible improvement from switching to v7 generally come from tables of tens of millions of rows and up.
The sorting benefit has a price, and this is the part most v7 introductions omit.
Since the first 48 bits are a millisecond timestamp, anyone can recover the creation time from a v7 value. If a user ID is v7 and appears in a public profile URL, that person's sign-up time becomes public. For an order ID it is the order time; for a document ID, the authoring time.
Comparing two v7 values tells you which came first. A competitor can sign up, compare their own ID with another, and estimate how many records were created in between. The 74 random bits prevent an exact count, but the time range is fully exposed.
A common compromise is to separate internal and external identifiers. Keep a v7 primary key for the index benefit and expose a separate v4 or short slug in public URLs. It costs one extra column and gives you both properties.
Safe in the sense that it leaks no timestamp. But v4 is not a secret either — it is merely hard to guess, and cannot replace access control. A design where "anyone with the URL can view it" is weak regardless of UUID version.
Storing a UUID as CHAR(36) uses 36 bytes including hyphens; BINARY(16) stores the same value in 16. On a primary key, that 20-byte difference multiplies across every secondary index. The cost is that humans can no longer read it or grep it out of a log. The hex tabs in the UUID converter convert between the two forms.
ULID also puts a 48-bit timestamp first, followed by 80 random bits, so its ordering property matches v7. The difference is representation: Crockford base32 yields a 26-character string, shorter than UUID's 36, using characters chosen to avoid visual confusion. In exchange it does not drop into a native UUID column.
If your database has a UUID type and your code already handles UUIDs, v7 is the natural fit. If the value is read by people in URLs or logs and shorter is better, ULID wins. Mixing both is not advisable.
There is no way to convert stored v4 values into v7 — the creation time was never in them. So a switch always means "only new values are v7", and the table keeps both versions side by side.
If queries or pagination assume "ordering by primary key means chronological", rows from the v4 era sit at random positions and results look wrong. Record the cut-over point and sort older data by an explicit created_at column. If you need time ordering at all, an indexed timestamp column is more explicit than relying on a UUID version.
v7 is a relatively recent standard, so support varies by language and library version. Verify that your database driver, ORM and any validating schema (for example JSON Schema's format: uuid) accept version 7. The browser's crypto.randomUUID() produces v4 only.
Request trace IDs, idempotency keys and filenames also use UUIDs. In those positions ordering is not a benefit and the exposed timestamp is pure downside. Decide per use site rather than standardising everything on v7.
BINARY(16) storage beats CHAR(36), and on a primary key that difference multiplies across every index.Generate and compare values in the UUID converter by switching the generation mode between v4, v7 and ULID, and use the hex tabs to see the 16-byte form. The Unix timestamp converter helps when you want to check what time a v7 prefix actually encodes.