UUID versions explained
Eight versions exist and three of them matter. Which one to reach for, what each gives away, and the measurements behind both answers.
Free toolUUID GeneratorVersion 4, 7, 1, 5 and nil identifiers, one or ten thousand at a time, from your own browser. Reads a UUID back apart too.Open the generatorThe short answer
Version 4 for anything, version 7 for a database primary key. Version 4 is 122 random bits and nothing else, which is what you want when an identifier only has to be unique. Version 7 puts a millisecond timestamp at the front, so a column of them sorts and inserts in order, which is what a B-tree index wants.
Version 5 is the third one worth knowing: it is a hash, so the same input always produces the same identifier. Version 1 is the format everything used before 2005 and the only reason to choose it now is that something else demands it. The rest are history or blank space.
| Version | What is inside it | Sorts? | Use it when |
|---|---|---|---|
| 4 | 122 random bits. | No | The default. Anything that just has to be unique. |
| 7 | 48-bit millisecond clock, 12-bit counter, 62 random bits. | Yes | A primary key, or anything you will sort by creation time. |
| 5 | SHA-1 of a namespace and a name. | No | The same input must always give the same identifier. |
| 1 | 100-nanosecond clock since 1582, plus a node field. | No | Something you do not control requires it. |
| 6 | The same fields as version 1, reordered so they sort. | Yes | You already have version 1 data and need it to sort. |
| 3 | MD5 of a namespace and a name. | No | Never, for new work. It is version 5 with a worse hash. |
| 2 | A version 1 with half the clock replaced by a POSIX id. | No | Never. It was only ever specified inside DCE. |
| 8 | Whatever you put in it. | Depends | You are defining your own format and want a version number for it. |
What we measured
Three things, all run in Chrome 152 on an Apple M1 Max with 32 GB, on macOS 26.6.2, on 2 September 2026. The generator being measured is the one on the UUID generator page, driven through its own controls rather than through a copy of the code, so what is timed is the whole path from pressing the button to the identifiers being on screen.
1. Version 7 does not sort unless it carries a counter
This is the part that gets left out. A version 7 UUID is a millisecond timestamp followed by random bits, so two made inside the same millisecond sort against each other at random. On a modern machine that is not an edge case: the run below produced 100,000 identifiers inside two milliseconds, which is about 50,000 per millisecond.
RFC 9562 §6.2 offers a fix, and method 1 is to use the twelve rand_a bits as a counter that increments within each millisecond. The table is the same 100,000 identifiers generated both ways, counting adjacent pairs that came out in the wrong lexicographic order.
| rand_a holds | Pairs out of order | Duplicates | Time for 100,000 |
|---|---|---|---|
| Random bits | 50,011 of 99,999 | 0 | 18.0 ms |
| A counter | 0 of 99,999 | 0 | 25.6 ms |
Half the pairs, which is exactly what a coin toss predicts once the timestamps are equal. The counter costs 7.6 ms over 100,000 identifiers, or 76 nanoseconds each, and it is the difference between a version that does its one job and a version that does not. Check whichever library you are using: not all of them implement it, and the failure is invisible until you sort something.
2. Where the randomness actually comes from, tested
A full collision cannot be reached in a browser, so the generator was tested on a deliberately narrow field instead: the first 32 random bits of its own output, drawn until one repeated, 200 times over. If those bits are uniform, the birthday problem says the first repeat should turn up after about sqrt(pi / 2 × 2^32) draws.
| Measure | Value |
|---|---|
| Trials | 200 |
| Predicted first repeat | 82,137 draws |
| Measured mean | 85,399 draws |
| Standard deviation | 43,722 |
| Standard error of the mean | 3,092 |
| Difference from prediction | 1.06 standard errors |
Within one standard error, which is the answer you want. Push the same arithmetic out to the 122 random bits a real version 4 carries and you get about 2.7 quintillion identifiers before a collision reaches even a one in a billion chance. That is the number people quote, and this is the check that the generator in front of you is actually drawing from the space the number assumes.
The caveat matters more than the result. The maths holds only for a cryptographic source. A version 4 built on Math.random looks identical, passes this same test at 32 bits, and still collides in production, because the state behind it is far smaller than 122 bits. That is where real duplicate-ID incidents come from, not from the birthday bound.
3. How long a batch actually takes
Median of nine presses, measured from the click to the identifiers being rendered. Every version fills one buffer from a single call to the platform's random number generator rather than calling it once per identifier, which is where the numbers come from.
| Version | 1 | 1,000 | 10,000 |
|---|---|---|---|
| 4 | 0.1 ms | 3.0 ms | 23.4 ms |
| 7 | 0.1 ms | 2.6 ms | 24.3 ms |
| 1 | 0.1 ms | 2.9 ms | 27.2 ms |
Version 1 is the slowest because its 60-bit clock passes what a JavaScript number can hold exactly, so every identifier costs a handful of BigInt operations. It is 3.8 ms over ten thousand, which is a reason to know the number and not a reason to avoid the version.
What each version gives away
An identifier is often visible in a URL, a log line or an API response, so it is worth knowing what a stranger can read out of one. Paste any UUID into the reader at the bottom of the generator and it will tell you all of this.
| Version | A stranger can read | Matters when |
|---|---|---|
| 4 | Nothing at all. | Never. |
| 7 | The millisecond it was created. | Row creation times are sensitive, or the count of them is. |
| 1 | The moment, to 100 nanoseconds, and the node field. | Always. See below. |
| 5 | Nothing directly, but the same input gives the same output, so a guessable name is a guessable identifier. | The name is an email address or an account number. |
The version 1 node field, measured on a real service
A version 1 UUID ends with 48 bits called the node. The 1980s intent was the machine's MAC address, which is how a version 1 was made unique across machines. RFC 9562 §6.10 now says to use random data instead, with the low bit of the first octet set to 1 to mark it as not a real hardware address.
Whether a given generator does that is checkable, and worth checking. Two separate batches of ten version 1 identifiers were taken from uuidtools.com on 2 September 2026. Every one of the twenty ended in the same node, 32:50:96:b3:9f:47, and its first octet is 0x32, whose low bit is 0. That is a real MAC address, and it is theirs: the server's, not yours.
Nothing about that is malicious, and it is a fair reading of the original specification. It is worth knowing for two reasons. The uniqueness property version 1 was built on does not apply when every identifier shares one node, and any version 1 from a website carries a stable fingerprint of the machine that made it. A browser cannot read a MAC address at all, which is why the generator here uses a random node with the multicast bit set, and why the reader will tell you which kind you are holding.
Making one in your own code
The one line per language, so you do not need a website in a script. Version 4 first, then version 7 where the standard library or the common library has it.
| Language | Version 4 | Version 7 |
|---|---|---|
| JavaScript | crypto.randomUUID() | uuid package, v7() |
| Python | uuid.uuid4() | uuid.uuid7() from 3.14, or uuid6 before that |
| Java | UUID.randomUUID() | com.fasterxml.uuid.Generators.timeBasedEpochGenerator() |
| C# | Guid.NewGuid() | Guid.CreateVersion7() from .NET 9 |
| Go | uuid.New() | uuid.NewV7() |
| Rust | Uuid::new_v4() | Uuid::now_v7() |
| PHP | Uuid::uuid4(), ramsey/uuid | Uuid::uuid7() |
| Ruby | SecureRandom.uuid | SecureRandom.uuid_v7 from 3.3 |
And in a database
| Database | The call | Notes |
|---|---|---|
| PostgreSQL | gen_random_uuid(), uuidv7() | Version 4 is built in from 13, version 7 from 18. Store it as uuid. |
| SQL Server | NEWID(), NEWSEQUENTIALID() | NEWID is version 4. NEWSEQUENTIALID sorts, but only within one server restart, and it is not a standard UUID version. |
| MySQL and MariaDB | UUID() | Version 1, with the server's node. Store it with UUID_TO_BIN(x, 1), whose second argument reorders the time fields so the value sorts. |
| SQLite | None | Generate it in your application and store 16 bytes as a BLOB. |
| MongoDB | UUID() in the shell | The default _id is an ObjectId, not a UUID. It is 12 bytes and already time-ordered, so on MongoDB the version 7 argument is usually moot. |
When a UUID is the wrong choice
Three cases, and all three come up more often than the version question does.
When a human has to read it out. Thirty-six characters is unusable on the phone, in a support ticket or on a printed label. Keep the UUID as the internal key and give the object a short public reference beside it.
When it needs to be unguessable. A UUID is an identifier, not a token. Use 256 bits of randomness from your platform's secure generator and treat it as a secret, including not logging it.
When a plain integer would do. A bigint is 8 bytes rather than 16, it sorts, it is readable, and every database has a fast path for it. UUIDs earn their keys when identifiers must be created in more than one place at once, offline, or before the row reaches a server. If none of that is true, the integer is the simpler answer.
Every measurement on this page was taken on 2 September 2026 and can be repeated. The timings and the ordering test run against the generator itself, in your own browser, and the node field result is one paste into the reader at the bottom of that page.