crypto.randomUUID() returns a new version 4 UUID as a lowercase 36-character string: 122 bits from the platform’s cryptographic random source, plus the 6 version and variant bits that RFC 9562 fixes.
console.log(crypto.randomUUID());
7a3a3c42-8843-42c3-9d4a-21b87044e7f6
That’s one run in Node 22. Given that UUID’s own 32 hex digits as its entropy, the tool’s core returns the same UUID, since the version and variant bits are already in place. The tool below never shows a fixed UUID, though: once the page loads, it draws fresh bytes from your browser’s crypto.getRandomValues.
Where it works
- Browsers have it only in secure contexts: HTTPS pages and
http://localhost. On a plain-HTTP page, such as a dev server opened by its LAN address, the function doesn’t exist. Chromium 153 onhttp://192.168.1.232:44421/threwTypeError: crypto.randomUUID is not a function, and WebKit 26.6 did the same. - Node has
cryptoas a global from Node 19. In a Node 18 scriptcryptois undefined; import it instead withimport { randomUUID } from 'node:crypto'.
crypto.getRandomValues works outside secure contexts too, so a fallback can set the bits itself:
function uuidv4() {
const b = crypto.getRandomValues(new Uint8Array(16));
b[6] = (b[6] & 0x0f) | 0x40; // version 4
b[8] = (b[8] & 0x3f) | 0x80; // variant 10
const h = Array.from(b, (x) => x.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)}`;
}
console.log(uuidv4());
d98ae785-600f-40a5-b5f1-6d066f34583b
Those are the same two writes the tool makes over its random bytes.
Why not Math.random
This snippet is all over the web, and its output looks right:
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
});
86e5afa9-67b5-486a-ba40-3a63d2fc5700
The tool’s decoder reads it as a valid version 4, because nothing in a UUID records how its bits were drawn. But ECMAScript doesn’t require Math.random() to be unpredictable, and V8 implements it with xorshift128+, whose internal state can be worked out from a handful of outputs. After that, every later ID can be predicted. Use crypto.
Version 7
There’s no built-in version 7. The uuid package has had v7() since its version 10; with [email protected]:
import { v4, v7 } from 'uuid';
console.log(v4());
console.log(v7());
console.log(v7());
5cf9c437-c2ea-4ca9-bf4f-c0b08605a606
01a13cd0-d7d0-73e8-8733-1ca638209706
01a13cd0-d7d0-73e8-8733-22296a376c48
The decoder puts both version 7 UUIDs at 2026-10-14T23:48:02.128Z, the same millisecond, and the second still sorts after the first.