UUID Generator
122 random bits. Reveals nothing about when or where it was made, and sorts in no useful order.
This batch
0 version 4 identifiers, each 36 characters. Every one is drawn from crypto.getRandomValues, never Math.random.
Why version 7 exists. A version 4 identifier used as a clustered primary key writes to a random point in the index every time, so the pages a database needs are scattered across the disk and the cache and each insert dirties another one. Version 7 begins with the timestamp, so consecutive inserts land next to each other and the index grows at one end — the same reason an auto-increment column is fast, without needing the database to hand out the number.
The trade is disclosure: a version 7 identifier states, to the millisecond, when the row it names was created. That is visible to anyone who receives it, so it is fine for an order id and wrong for anything where the creation time is itself private. It is also not a secret in either version — use a token for that, not an id.
Identifiers nobody has to hand out
The point of a 128-bit identifier is that two machines that have never spoken can each invent one and neither will collide with the other: no sequence to reserve, no round trip to learn what the new row is called, no gap in the numbering when a transaction rolls back. This generator makes them in the two versions worth using today, one at a time or a thousand at once.
It also inspects an identifier you already have, reporting version, variant and — for version 7 — the moment it was created.
What version 4 spends its bits on
A version 4 identifier is 128 bits of which 122 are random. Six are fixed by the specification: four say “version 4” in the thirteenth hex digit, and two mark the variant at the seventeenth, which is why that position is always 8, 9, a or b. Both are readable by eye — 550e8400-e29b-41d4-a716-446655440000 has a 4 and an a in exactly those places.
At 122 random bits, the birthday bound puts even odds of a single repeat at roughly 2.7 quintillion identifiers, so a billion a second would take about 85 years to get there. Where the randomness came from matters far more: every byte here comes from crypto.getRandomValues. A generator built on Math.random can hand two tabs the same sequence, and uniqueness becomes a coin toss.
Version 7, and the index it stops thrashing
Version 4 is unordered by design, and that becomes expensive the moment one is a primary key. A B-tree index keeps its entries sorted, so a random key inserts into a random leaf: the page needed is rarely the page in memory, every insert dirties another, and pages split all over the tree instead of filling neatly.
Version 7 puts a 48-bit Unix millisecond timestamp in the leading bits, then the version, then randomness. Consecutive inserts land together and the index grows at one end — what makes an auto-increment column fast, without anything having to issue the number. Sorting the text sorts by creation time, so “the most recent hundred rows” becomes a range scan.
Two values made in the same millisecond would still be in arbitrary order, so the twelve bits after the timestamp count within each millisecond. A batch generated in one tick comes out in the order it was made, which you can see by generating a hundred and reading down the list.
The trade version 7 asks you to accept
A version 7 identifier announces when the thing it names was created, to the millisecond, to everyone who receives it. For an order id that is harmless and often handy. For a password reset, an invitation, or anything where the creation time is itself the sensitive fact, version 4 is the right answer.
Neither version is a secret. Both are built to be unique, not unguessable, and a version 7 value narrows the search for anyone who knows roughly when a record was made. Anything granting access needs a random token rather than an identifier doing double duty.
The older versions, and how to store any of them
Versions 1 and 6 are time-based and traditionally embed the network card’s address, which is why they fell from favour. Versions 3 and 5 hash a namespace and a name, so they are deterministic — useful when one input must always give one identifier — and version 8 is a free-form slot.
However they are made, store them as 16 bytes rather than 36 characters of text. PostgreSQL has a native uuid type and MySQL has BINARY(16); against CHAR(36) that saves more than half the space in the column and in every index touching it.
Collisions, version 7 keys and braces
Could two of these ever come out the same?
Not in any realistic amount of use. Version 4 draws 122 random bits, and even odds of one repeat arrive only after quintillions of values. The real risk is a weak random source, which is why this one uses the platform’s cryptographic generator.
Should I switch my primary keys to version 7?
For a new table whose keys are already random identifiers, yes: the same properties with a far friendlier insert pattern. For an existing table it is a migration, worth doing only if index churn is a measured problem rather than a suspicion.
Is it safe to put one in a URL?
Safe to expose, yes: neither version reveals anything about your system beyond version 7’s timestamp. Safe as the only thing guarding a resource, no — an identifier in a link is not authorisation, and treating it as one is how private pages get shared by accident.
Why do some tools print them in braces or without hyphens?
Braces are a Microsoft convention from the GUID world, and the unhyphenated 32-character form is common in URLs and storage keys. All three carry the same 128 bits, and the inspector accepts each of them.
How much does storing one as text actually cost?
The 36-character form takes 36 bytes against the binary form’s 16, and that overhead repeats in every index and every foreign key pointing at the column. On a table of a hundred million rows the difference runs to gigabytes.
Are ULIDs and version 7 the same idea?
Close enough that the choice rarely matters: both put a millisecond timestamp in the leading bits so values sort by creation time. ULID came first and carries its own 26-character text form, while version 7 is the standardised shape and drops into any column already holding UUIDs.
Can I generate a version 5 identifier here?
Not here — this generator makes versions 4 and 7. A version 5 value is a hash of a namespace and a name, so it needs both of those as input and is deterministic rather than random.