The native API: crypto.randomUUID()
JavaScript has had a native UUID v4 generator since the Web Crypto API was standardised. It requires no library, no bundler configuration, and no polyfill in any environment that matters in 2026:
// Browser
const id = crypto.randomUUID();
// → "b4c7e2a1-3f8d-4b2e-9c5a-1d6e7f8a9b0c"
// Node.js (built-in, no import needed in globals context)
const id = crypto.randomUUID();
// Node.js (explicit import — preferred for clarity)
import { randomUUID } from 'node:crypto';
const id = randomUUID();
crypto.randomUUID() is RFC 9562-compliant, draws from the operating system’s CSPRNG, and is the right default for v4 in any JavaScript project. There is no reason to reach for a library for v4 alone.
UUID v7 in JavaScript
The built-in crypto.randomUUID() produces v4 only. For v7 you have two options: a library or a short implementation.
Using the uuid package
The uuid package (v9.0.0+) exports v7:
import { v7 as uuidv7 } from 'uuid';
const id = uuidv7();
// → "018f3c4e-7a21-7b3c-9d4e-5f6a7b8c9d0e"
Install it:
npm install uuid
The package is tree-shakeable, so importing only v7 keeps the bundle small. It handles the monotonic counter (RFC 9562 §6.2 Method 1) correctly, so multiple calls within the same millisecond sort in generation order.
A minimal implementation
If you want zero dependencies, here is a self-contained v7 generator that matches this site’s implementation:
function makeUuidv7() {
let lastMs = 0, seq = 0;
return function uuidv7() {
const ms = Date.now();
if (ms === lastMs) {
seq = (seq + 1) & 0x0fff;
} else {
lastMs = ms;
seq = 0;
}
const r = crypto.getRandomValues(new Uint8Array(8));
const b = new Uint8Array(16);
// 48-bit big-endian timestamp
b[0] = Math.floor(ms / 2 ** 40) & 0xff;
b[1] = Math.floor(ms / 2 ** 32) & 0xff;
b[2] = Math.floor(ms / 2 ** 24) & 0xff;
b[3] = Math.floor(ms / 2 ** 16) & 0xff;
b[4] = Math.floor(ms / 2 ** 8) & 0xff;
b[5] = ms & 0xff;
// version 7, 12-bit counter
b[6] = 0x70 | ((seq >> 8) & 0x0f);
b[7] = seq & 0xff;
// variant 0b10, random bytes
b[8] = 0x80 | (r[0] & 0x3f);
b[9] = r[1]; b[10] = r[2]; b[11] = r[3];
b[12] = r[4]; b[13] = r[5]; b[14] = r[6]; b[15] = r[7];
let h = '';
for (let i = 0; i < 16; i++) h += b[i].toString(16).padStart(2, '0');
return `${h.slice(0,8)}-${h.slice(8,12)}-${h.slice(12,16)}-${h.slice(16,20)}-${h.slice(20)}`;
};
}
const uuidv7 = makeUuidv7();
The factory pattern (makeUuidv7()) is important — it keeps the monotonic counter inside a closure, so the counter is shared only within one generator instance. In a Node.js server, create one instance at module load time.
React patterns
IDs for DOM elements
React components often need a stable ID for aria-labelledby, htmlFor, or id attributes. useId() (React 18+) is the right tool for this — it is deterministic across server and client and avoids hydration mismatches:
import { useId } from 'react';
function TextInput({ label }) {
const id = useId();
return (
<>
<label htmlFor={id}>{label}</label>
<input id={id} type="text" />
</>
);
}
Do not use crypto.randomUUID() for DOM IDs — it generates a new value on every render, which causes unnecessary re-renders and breaks server-side rendering.
Record IDs in client state
When creating a new record optimistically before it is saved to the server, a UUID makes a good temporary key:
import { v7 as uuidv7 } from 'uuid';
function addItem(name) {
return { id: uuidv7(), name, status: 'pending' };
}
Use v7 here if the records will end up in a database (the ID can become the permanent primary key). Use v4 if the ID is only for React’s reconciliation and the server will assign its own ID.
Vue patterns
Same principle in Vue — useId() is the Composition API equivalent for DOM binding; generate UUIDs only for real record identities:
import { ref } from 'vue';
import { v7 as uuidv7 } from 'uuid';
const items = ref([]);
function addItem(name) {
items.value.push({ id: uuidv7(), name });
}
Prisma
Prisma supports UUID v4 natively via @default(uuid()). For v7, generate the value in application code and pass it in, or use a database-level default (uuidv7() in PostgreSQL 18):
model User {
id String @id @default(uuid()) // v4, generated by Prisma
createdAt DateTime @default(now())
}
For v7 with application-side generation:
model Event {
id String @id // no default — application provides a v7 UUID
name String
}
import { v7 as uuidv7 } from 'uuid';
import { prisma } from './db';
await prisma.event.create({
data: { id: uuidv7(), name: 'page_view' },
});
Prisma 5.x adds @default(cuid()) and @default(uuid(7)) — check the current version of the Prisma docs for the latest UUID v7 support status.
Drizzle ORM
Drizzle has native UUID column helpers for PostgreSQL:
import { pgTable, uuid, text } from 'drizzle-orm/pg-core';
import { sql } from 'drizzle-orm';
// v4 — Drizzle generates in JS
export const users = pgTable('users', {
id: uuid('id').defaultRandom().primaryKey(),
name: text('name').notNull(),
});
// v7 — database-level default (PostgreSQL 18+)
export const events = pgTable('events', {
id: uuid('id').default(sql`uuidv7()`).primaryKey(),
name: text('name').notNull(),
});
For other databases or older PostgreSQL, generate v7 in application code:
import { v7 as uuidv7 } from 'uuid';
import { db } from './db';
import { events } from './schema';
await db.insert(events).values({ id: uuidv7(), name: 'checkout' });
TypeScript: typing UUID values
TypeScript’s string covers UUID values, but a branded type catches mistakes early:
type UUID = string & { readonly __brand: 'UUID' };
function asUUID(s: string): UUID {
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(s)) {
throw new TypeError(`Not a valid UUID: ${s}`);
}
return s as UUID;
}
// Or trust the source and cast directly when generating
const id = crypto.randomUUID() as UUID;
The brand prevents accidentally passing a raw string where a validated UUID is expected, without any runtime overhead after the initial check.
Frequently asked questions
Does JavaScript have a built-in UUID generator?
Yes for v4: crypto.randomUUID() is available in all modern browsers and Node.js 19+. For v7 there is no built-in — use a library like the uuid npm package or a short RFC 9562-compliant implementation.
How do I generate a UUID in Node.js?
Use the built-in crypto module: import { randomUUID } from 'node:crypto', then call randomUUID(). This produces a RFC 9562-compliant v4. For v7 in Node.js, the uuid package (v9+) exports v7().
Can I generate UUIDs offline?
Yes. Once the page has loaded, generation is fully client-side and works with no network connection.
Is crypto.randomUUID() available everywhere?
In browsers, yes — it has been supported since Chrome 92, Firefox 95, and Safari 15.4, and is available in all modern environments. In Node.js it was added in v14.17.0 as part of the built-in crypto module.
What is the best npm package for UUIDs?
The uuid package (npmjs.com/package/uuid) is the standard choice — well-maintained, tree-shakeable, and it supports v1, v4, v5, v6 and v7. For v4 only, the native crypto.randomUUID() needs no package at all.