albert.walickihire me
← all solutions
javascript

How to generate a UUID in JavaScript?

Generate a UUID with crypto.randomUUID in the browser and Node, a getRandomValues fallback for plain HTTP pages, and when UUID v7 is the better choice.

Call crypto.randomUUID(). It returns a random version 4 UUID as a 36-character string, works in all modern browsers and in Node, and needs no package.

const id = crypto.randomUUID();
console.log(id); // '5111a40b-6713-42c9-b9be-f45d7b24d441'

The values come from a cryptographically secure random generator, so the IDs are unique for any practical purpose and can't be guessed.

Browsers: secure contexts only

In browsers, crypto.randomUUID() only exists in secure contexts: pages served over HTTPS, or from localhost. On a plain HTTP page it's undefined, and calling it throws a TypeError.

This often shows up during development. The app works on localhost, but when you open the dev server on your phone through your computer's IP address, like http://192.168.1.20:3000, the page is no longer a secure context and the call fails.

In Node, crypto is a global in current versions, so the same line works. You can also import it explicitly:

import { randomUUID } from 'node:crypto';

const id = randomUUID();

A fallback for plain HTTP

crypto.getRandomValues() is available on HTTP pages too, so you can build a v4 UUID from 16 random bytes. Two bytes get fixed bits: the version (the first digit of the third group is always 4) and the variant (the first digit of the fourth group is 8, 9, a or b).

function uuidv4() {
  const bytes = crypto.getRandomValues(new Uint8Array(16));

  bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
  bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant

  const hex = [...bytes]
    .map((byte) => byte.toString(16).padStart(2, '0'))
    .join('');

  return [
    hex.slice(0, 8),
    hex.slice(8, 12),
    hex.slice(12, 16),
    hex.slice(16, 20),
    hex.slice(20),
  ].join('-');
}

const id = crypto.randomUUID?.() ?? uuidv4();
// e.g. '55c0201b-b259-4f54-b3c0-8fcdd65b3735'

The last line uses the native method when it exists and the fallback otherwise.

Don't use Math.random()

You'll find short snippets that fill 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' with Math.random(). They produce the right format, but Math.random() isn't cryptographically secure, and its output can be predicted. Don't use it for anything that has to be unique or hard to guess, like invite links, file names on a server or tokens.

In React, you don't need a UUID to connect a label to an input. useId() generates an ID that matches between the server and the client.

UUID v7 for database keys

A v4 UUID is completely random, so new rows land in random places in a database index. On large tables, that makes inserts slower than with sequential IDs. UUID v7 starts with a timestamp in milliseconds, so newer IDs sort after older ones and new rows are added at the end of the index.

crypto.randomUUID() only makes v4. For v7, the uuid package has a function:

import { v7 as uuidv7 } from 'uuid';

const id = uuidv7();
// e.g. '01a0aa16-8e00-7c3a-9f41-2b6d5e8a7c10'

The timestamp is readable by anyone who sees the ID, so v7 reveals when a record was created. If that's sensitive, for example in public URLs, stick with v4.

more solutions
work with me

Got something that needs building?

Frontend builds, full-stack features in Django, design-system work. Available for work.

See my workGet in touch