UUID Generator
Generate UUIDs in bulk, in your browser. Version 4 for a plain random identifier, or the time-ordered version 7 that makes a far better database key: with the timestamp inside each one shown, so you can see it working.
UUIDs
Common mistakes
These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
Using v4 as a database primary key
It is fully random, so inserts land anywhere in the index and fragment it badly. On a large table this is a measurable write penalty.
Instead:Use v7, which is time-ordered and indexes like a sequential key while staying unique.
Treating a UUID as unguessable
v4 is random and effectively unguessable. v1 and v7 encode a timestamp, and v1 historically encoded a MAC address.
Instead:Use v4 for anything that must not be predictable.
Storing a UUID as a 36-character string
That is more than double the 16 bytes it needs, in every row and every index.
Instead:Store as binary or the database's native uuid type.
Why this one
A UUID generator is one line of code. Choosing the right version is the part that shows up in a slow query six months later.
Version 7, which most generators skip
The first 48 bits of a v7 are a millisecond timestamp, so the values sort by creation time. That single property is why v7 exists: it makes a UUID usable as a primary key without the index fragmentation a random v4 causes.
The timestamp is shown, not hidden
Every v7 value here is printed with the date encoded inside it. That is useful for confirming the version works, and it is the argument against using v7 where creation time is sensitive or where a sortable id lets someone count your records.
From the platform, not from us
Version 4 uses crypto.randomUUID where the browser provides it, and crypto.getRandomValues otherwise. Nothing here is seeded by Math.random, which has no security claim and produces values an attacker can predict from earlier output.
The formats that actually get asked for
Canonical, uppercase, no hyphens, brace-wrapped for the Microsoft world, and the urn:uuid: form. Postgres accepts the compact form into a uuid column and hands back the canonical one; some other parsers reject it outright.
What is a UUID, and which version should you use?
A UUID is 128 bits, written as 32 hex characters in five groups. The point of it is that two machines that have never communicated can each mint one and be confident they will not collide, no coordination, no central sequence, no round trip to a database to find out what the next id is.
The layout, and where the version hides
Two positions are not random. The first character of the third group is the version number, and the first character of the fourth group encodes the variant: it is always 8, 9, a or b for the UUIDs anyone uses today. Everything else depends on the version. That is why you can read a UUID's version straight off the string.
018f4c2e-6b3d-7a91-b2c4-5e8f9a0d1c3b
| |
| +-- variant: 8, 9, a or b
+------- version: 7 here, 4 for a random UUID
8-4-4-4-12 hex characters, 128 bits, 122 of them free in a v4 Version 4 is 122 random bits
Six bits are spent on the version and variant fields and the rest are drawn from the operating system's cryptographic generator. Collisions are not a practical concern: you would need to produce about a billion a second for 85 years to reach a 50% chance of one. If you are seeing duplicates, something is reusing a seed or copying a value: it is never bad luck.
Why a random UUID makes a poor primary key
A B-tree index keeps its entries in sorted order. Sequential keys append at the right-hand edge, so the same few pages stay in memory and stay full. Random keys land anywhere, so almost every insert dirties a different page, pages split half-empty, and the working set becomes the whole index rather than its tail. On a large table this shows up as write throughput that degrades as the table grows, which is a difficult symptom to attribute back to a choice made on day one.
v4 inserts: ...4f2a... ...b91c... ...0e73... scattered
v7 inserts: ...018f4c2e01 ...018f4c2e02 ...018f4c2e03 appended Version 7 puts the time first
The first 48 bits are a Unix timestamp in milliseconds, so sorting v7 values as strings sorts them by creation time and inserts arrive in order. It was standardised in RFC 9562 in 2024 alongside versions 6 and 8, replacing the old RFC 4122. The trade is that the creation time is readable by anyone holding the value, and an ordered id lets an outsider estimate how many you have issued, so v7 is the right default for internal keys and the wrong one for a public identifier.
Where ULID and the others fit
ULID and KSUID solved the sortable-id problem years before v7 was standardised, and they work well. The reason to prefer v7 now is that it is a UUID: it fits a native uuid column in Postgres, every language has a parser, and no library is required to read one. If you already run ULIDs there is no urgency to move, and for anything new v7 is the fewer moving parts.