UUID generator

Version 4 and version 7 UUIDs to RFC 9562, generated in your browser from the operating system CSPRNG.

G

Which version you want

Almost every UUID in the wild is version 4: 122 bits of randomness with six bits spent on the version and variant fields. It is unguessable, it needs no coordination between machines, and its collision probability is negligible at any scale you will meet.

Version 7 was standardised in May 2024 by RFC 9562, which replaced RFC 4122. It puts a 48-bit millisecond timestamp at the front and fills the remaining 74 bits with randomness, so sorting a list of them sorts by creation time. That single property is why it has taken over as the default recommendation for database primary keys.

The other versions still exist and still have uses, but none of them is what you want for a new identifier unless you already know why.

All versions defined by RFC 9562
VersionBuilt fromRandom bitsSorts by timeUse it when
v1Timestamp plus node ID~60NoLegacy systems only. The node field is often a MAC address.
v3MD5 of namespace and name0NoYou need the same input to always give the same UUID.
v4Randomness122NoYou want an unguessable identifier and nothing more.
v5SHA-1 of namespace and name0NoSame as v3, with a better hash. Prefer over v3.
v6Reordered v1~60YesYou are migrating v1 data and need it to sort.
v7Timestamp plus randomness74YesDatabase keys, event IDs, anything you insert a lot of.
v8Whatever you defineYour choiceYour choiceYou have a custom layout and want a valid version field.

Name-based UUIDs (v3 and v5) are deterministic by design. The same namespace and name always produce the same value, so they must never be used where the identifier needs to be unguessable.

How a UUID is laid out

A UUID is 128 bits rendered as 32 hexadecimal digits in five hyphenated groups of 8-4-4-4-12. Two of those digits are not random in any version: the first digit of the third group is the version number, and the first digit of the fourth group carries the two-bit variant.

That is why every v4 UUID has a 4 in position 15 and a character from 8, 9, a or b in position 20. If you are validating UUIDs with a regular expression and it does not check those two positions, it will accept values that are not valid UUIDs.

Version 7 field layout, from RFC 9562 section 5.7
BitsFieldContents
0-47unix_ts_msBig-endian milliseconds since the Unix epoch
48-51verAlways 0111, which renders as the digit 7
52-63rand_a12 bits, optionally a sub-millisecond counter
64-65varAlways 10
66-127rand_b62 random bits

Collisions, with the actual numbers

Version 4 has 122 random bits, which is 5.3 undecillion possible values. To reach a one in a billion chance of a single collision you would need to generate about 103 trillion of them. At a million per second that is over three years of continuous generation before the odds become worth thinking about.

Version 7 has 74 random bits, but they only have to be unique within a single millisecond, since the timestamp separates everything else. Within one millisecond, a 1% collision chance arrives at around 19.5 billion UUIDs. No system generates that in a millisecond.

The practical risk with either version is not the mathematics. It is a broken random source: a generator using Math.random(), or a container image that starts several instances from the same seeded state.

What we do differently

Every value here is produced from crypto.getRandomValues(), not Math.random(). Of the fifteen generators we audited on the first page of Google, one produces UUIDv4 using Math.random() and a bare toString(16), which RFC 9562 explicitly requires a cryptographic source for.

Our version 7 generator is monotonic. RFC 9562 section 6.2 allows a counter in the rand_a field so that two UUIDs created inside the same millisecond still sort in creation order. Without it, ordering within a millisecond is arbitrary, which shows up as out-of-order rows in exactly the high-insert workload version 7 exists to serve.

The tool also decodes what it produces. Paste any UUID into the inspector and it will tell you the version, the variant and, for time-based versions, the exact creation timestamp.

Doing this in your own code

JavaScript
// v4, built in since Node 19 and in every current browser.
crypto.randomUUID();

// Web Crypto has no v7. 48-bit big-endian millisecond timestamp,
// then 74 random bits around the version and variant fields.
function uuidv7() {
  const b = crypto.getRandomValues(new Uint8Array(16));
  const ts = Date.now();
  b[0] = (ts / 2 ** 40) & 0xff;
  b[1] = (ts / 2 ** 32) & 0xff;
  b[2] = (ts / 2 ** 24) & 0xff;
  b[3] = (ts / 2 ** 16) & 0xff;
  b[4] = (ts / 2 ** 8) & 0xff;
  b[5] = ts & 0xff;
  b[6] = (b[6] & 0x0f) | 0x70;  // version 7
  b[8] = (b[8] & 0x3f) | 0x80;  // variant 10
  const h = [...b].map((v) => v.toString(16).padStart(2, "0")).join("");
  return `${h.slice(0,8)}-${h.slice(8,12)}-${h.slice(12,16)}-${h.slice(16,20)}-${h.slice(20)}`;
}

crypto.randomUUID() only ever produces v4, in the browser and on Node alike. Node does now ship a native v7 as randomUUIDv7() on node:crypto, added in 24.16.0 and 26.1.0, but there is still no v7 anywhere in the Web Crypto API.

Python 3.6+
import uuid

uuid.uuid4()          # random
uuid.uuid5(uuid.NAMESPACE_DNS, "example.com")   # name based, deterministic

# Python 3.14 added uuid6(), uuid7() and uuid8() to the standard library.
uuid.uuid7()

# On 3.13 and earlier v7 needs a library:
#   pip install uuid6
from uuid6 import uuid7
uuid7()

uuid.uuid4() draws from os.urandom, so it is cryptographically secure. uuid.uuid8() is documented as not using a CSPRNG by default, so it is not a drop-in replacement for uuid4().

PostgreSQL
-- v4, built in since PostgreSQL 13.
SELECT gen_random_uuid();

-- v7 is native from PostgreSQL 18.
SELECT uuidv7();

-- As a primary key, v7 keeps inserts at the right edge of the index
-- instead of scattering them the way v4 does.
CREATE TABLE orders (
  id          uuid        PRIMARY KEY DEFAULT uuidv7(),
  placed_at   timestamptz NOT NULL DEFAULT now(),
  total_cents integer     NOT NULL
);
Go
import "github.com/google/uuid"

uuid.New()          // v4, panics on entropy failure
uuid.NewRandom()    // v4, returns an error instead
uuid.NewV7()        // v7, added in google/uuid v1.5.0
Java 17+
import java.util.UUID;

UUID.randomUUID();   // v4, backed by SecureRandom

// v7 is not in the JDK. java-uuid-generator, artifact
// com.fasterxml.uuid:java-uuid-generator:5.1.0
import com.fasterxml.uuid.Generators;
Generators.timeBasedEpochGenerator().generate();   // returns java.util.UUID
C# / .NET 9+
Guid.NewGuid();          // v4
Guid.CreateVersion7();   // v7, added in .NET 9

// Watch the byte order. Guid.ToByteArray() returns the first three
// fields little-endian, which is the classic mixed-endian GUID trap
// when moving values between .NET and anything else.
Guid.NewGuid().ToByteArray(bigEndian: true);

The mixed-endian layout is why a GUID can look different after a round trip through .NET.

Shell
# Linux, from the kernel
cat /proc/sys/kernel/random/uuid

# uuidgen, from util-linux
uuidgen --random     # v4
uuidgen --time       # v1

# Python one-liner, portable
python3 -c "import uuid; print(uuid.uuid4())"

Questions

Are these UUIDs unique?

Uniqueness is probabilistic, not guaranteed. For version 4 the chance of two colliding is negligible at any realistic scale: about 103 trillion UUIDs before a one in a billion chance of a single collision. What matters far more than the mathematics is that the randomness is real, which is why this tool uses the operating system CSPRNG and says so.

Should I use UUIDv7 instead of v4 for my database?

For a primary key, usually yes. Version 4 values are random, so inserts land at random points in the index and cause page splits and cache churn. Version 7 values increase over time, so inserts stay at the right edge of the B-tree. The tradeoff is that a v7 value discloses when the row was created, to the millisecond, which matters if the identifier is exposed publicly.

What is the difference between a UUID and a GUID?

They are the same 128-bit value. GUID is the Microsoft name for it. The one real difference is byte order: .NET historically serialises the first three fields little-endian, so the same UUID can render differently after a round trip through a Microsoft API. Guid.ToByteArray(bigEndian: true) avoids it.

Is it safe to use a UUID as a session token or password reset link?

A version 4 UUID has 122 bits of entropy from a secure source, which is more than enough. A version 1 or version 7 UUID is not appropriate, because a large part of the value is a predictable timestamp. If you are generating a bearer token, prefer a purpose-built random string.

Does the generator use crypto.randomUUID()?

No, and deliberately. crypto.randomUUID() only produces version 4, so a second implementation would be needed for version 7 anyway. One code path that can be read end to end is worth more than delegating half of it. The bytes come from the same crypto.getRandomValues() that backs the native function.

Related generators