UUID Generator
UUIDs in every version, formatted the way you need them, and one read back apart
Generate
Result
Never hand the same one out twice
Kept in this browser only, up to 10,000 values, oldest dropped first. It exists for the ordinary problem, which is a value that already went into a fixture or a seed script coming back out a second time. Two random version 4 UUIDs colliding on their own is not something you need protecting from.
Read one back
A UUID is sixteen bytes with six bits spoken for. What fills the other 122 is the only thing that separates one version from another.
f47ac10b - 58cc - 4372 - a567 - 0e02b2c3d479
4 bytes 2 2 2 6
^ ^
| '--- byte 8, top two bits forced to 10, so this
| digit is always 8, 9, a or b
'---------- byte 6, high nibble holds the versionThose two markers are what let you read a UUID by eye. The 13th hex digit is the version and the 17th is the variant, and they sit in the same place in every version there has ever been. Anything failing either test was not made by something following the specification, whatever it claims.
What each version puts in the other 122 bits
| Version | Carries | Sorts | Repeatable |
|---|---|---|---|
| 1 | Time, clock sequence, node | No | No |
| 3 | MD5 of a namespace and a name | No | Yes |
| 4 | 122 random bits | No | No |
| 5 | SHA-1 of a namespace and a name | No | Yes |
| 6 | The same as 1, reordered | Yes | No |
| 7 | Unix milliseconds, then random | Yes | No |
Version 2 exists, is called DCE Security, and is effectively never used. Version 8 is deliberately undefined: it marks a UUID whose contents are whatever the system that issued it decided, which makes it the right home for a custom layout and useless as a thing to generate at random.
Why version 7 is the one to reach for
Version 7 puts a 48-bit millisecond timestamp in the leading bits, so the values come out in the order they were made and sort correctly as text, as bytes, and as a database key. Behind the timestamp sit twelve bits and then 62 random ones.
018f4a2b7c3d 7 e91 a2b46f1c9d0e5a73
48 bits 4 12 2 + 62 bits
unix ms v count variant, then randomThose twelve bits are the interesting part. Left random, two UUIDs generated in the same millisecond can come out in either order. RFC 9562 section 6.2 offers a counter there instead. This tool does that, so a batch of ten thousand generated inside one millisecond is still strictly increasing. It costs twelve bits of randomness and leaves 62, which is far more than anything is going to exhaust.
Why the inserts got slower
Random primary keys land on random pages of a B-tree. Every insert dirties a different page, the hot set stops fitting in memory, and the index fragments. Sequential keys append to the same page over and over. This is the usual reason a table that behaved fine at a million rows stops behaving at fifty million, and it is most of why version 7 exists at all.
Storing them as text compounds it. The canonical string is 36 characters against 16 bytes of actual value, so a varchar(36) column more than doubles the storage and slows every comparison. Postgres has uuid, MySQL has BINARY(16), SQL Server has uniqueidentifier. Use them.
Version 1 used to leak the machine that made it
The node field was specified as the MAC address of the network card. That makes version 1 UUIDs unique across machines without any coordination, and it also means every identifier carries a permanent hardware serial number and the exact time it was created. It has been used to trace documents back to the computer that wrote them, in at least one criminal investigation.
A browser cannot see a MAC address and should not be handing one out if it could. RFC 9562 section 6.10 covers this: use random bits and set the multicast bit, which marks the value as something no real network card could have. That is what the node field here is, generated fresh for the tab.
Versions 3 and 5 are the ones that repeat
Give the same namespace and the same name and you get the same UUID, on any machine, forever. That is the point of them: an identifier you can recompute instead of storing it. That is how you give stable IDs to things that already have natural keys.
DNS 6ba7b810-9dad-11d1-80b4-00c04fd430c8
URL 6ba7b811-9dad-11d1-80b4-00c04fd430c8
OID 6ba7b812-9dad-11d1-80b4-00c04fd430c8
X.500 6ba7b814-9dad-11d1-80b4-00c04fd430c8Those four are defined in the specification, and any UUID at all can be used as a namespace of your own. That is the usual approach: generate one version 4 UUID, write it into the code as a constant, and derive everything under it.
Version 5 uses SHA-1 and version 3 uses MD5. Neither is a security decision. The hash is being used to spread names evenly across the space, not to resist anybody, and a UUID was never a secret to begin with. Prefer 5 for new work, use 3 only when something on the other side already does.
Why you cannot set the length here
This comes up, and the honest answer is that a UUID with a different number of characters, that is not a UUID. The 128 bits and the 8-4-4-4-12 shape are the format. A 20-character value fails uuid in Postgres, UUID.fromString in Java, uuid.UUID() in Python and every validator in between, and it fails at the far end of an integration instead of here, and that is the worst possible place to find out.
What you can change is how the same 128 bits are written down. Case, hyphens, braces, a urn:uuid: prefix, or Base64, which fits all sixteen bytes into 22 characters and is what people usually want when they say a UUID is too long for a URL. All of those decode back to the same value.
If what you actually want is a random identifier of your own length over your own alphabet, that is a different thing with a different name, and it lives next door.
Where the bits come from
crypto.getRandomValues, the same generator the browser uses for session tokens and key material. Not Math.random, which is seeded per page, recoverable from a handful of outputs, and perfectly good for animation jitter but not for anything somebody might want to guess.
122 bits is roughly 5.3 × 1036 possible values. Reaching a 50% chance of seeing any repeat takes about 2.7 quintillion of them, which is 86 years of generating a billion every second. Collisions are not the thing to worry about, and the memory of what this tool has handed out is not there to prevent them. It is there for the ordinary version of the problem: a value that already went into a fixture or a seed script quietly coming back out because you regenerated instead of scrolling up.
Unguessable is not the same as secret
A UUID in a URL is a good identifier and a poor access token. URLs turn up in proxy logs, Referer headers, browser history and pasted support tickets. If knowing the identifier is the thing that grants access, you have built a capability URL, and it needs what a password gets: short-lived, revocable, and kept out of anything that writes to disk.
Versions 1, 6 and 7 make this worse, because the timestamp inside them is readable. Paste one into the box above and it tells you the millisecond the record was created, which is occasionally a feature and occasionally a disclosure nobody intended.
Two special values, both defined in RFC 9562. All zeros is the nil UUID and conventionally means no value. All ones is the max UUID, added in 2024, and exists so that a range scan has something guaranteed to sort last. Neither has a valid version nibble, so neither will ever come out of a generator by accident.