Generate UUID v4 in JavaScript β Code Guide + Examples
Use the free online UUID v4 Generator directly in your browser β no install required.
Try UUID v4 Generator Online βEvery JavaScript application eventually needs unique identifiers β session tokens, database rows, idempotency keys for payment APIs, correlation IDs for distributed tracing. The simplest way to generate UUID v4 in JavaScript today is crypto.randomUUID(): zero dependencies, one line, cryptographically secure. UUID v4 is widely used precisely because it needs no coordination between services β client and server can both produce IDs independently without collision risk. This guide covers that built-in API, the uuid npm package, validation β all on Node.js 19+ and modern browsers. For a no-code option, the UUID v4 Generator on ToolDeck produces compliant identifiers instantly.
- βcrypto.randomUUID() is built into browsers and Node.js β zero dependencies, one line of code.
- βUUID v4 is a 128-bit random identifier: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx (y is 8, 9, a, or b).
- βValidate with /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i β checks version and variant bits.
- βThe uuid npm package adds v1, v3, v5, and v7 support when you need more than random IDs.
- βFor database primary keys, prefer UUID v7 (time-ordered) over v4 (random) to reduce index fragmentation.
What is UUID v4?
A UUID (Universally Unique Identifier) version 4 is a 128-bit random identifier formatted as 32 hexadecimal digits separated by four hyphens: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx. The 4 at position 15 marks the version. The y character at position 20 is one of 8, 9, a, or b (the RFC 4122 variant). The remaining 122 bits are random. UUID v4 is the most common version in JavaScript applications because it requires no coordination between systems β you can generate IDs independently on client and server without worrying about collisions.
// No identifier
const event = { action: "user.login", ts: 1711824000 };// With UUID v4
const event = {
id: "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
action: "user.login",
ts: 1711824000
};crypto.randomUUID() β The Native JavaScript Approach
crypto.randomUUID() is available in Chrome 92+, Firefox 95+, Safari 15.4+, and Node.js 19+ (with experimental support from Node.js 14.17.0 behind globalThis.crypto). It returns a lowercase 36-character UUID v4 string. No import needed in browser JavaScript. In Node.js, you can call it directly on the global crypto object or import it explicitly from the node:crypto module.
// Works in any modern browser β no build step, no bundler
const requestId = crypto.randomUUID();
console.log(requestId);
// "3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"
// Use it wherever you need a unique identifier
const telemetryEvent = {
event_id: crypto.randomUUID(),
action: "checkout.started",
session_id: crypto.randomUUID(),
timestamp: Date.now(),
cart_total_cents: 14999,
};
console.log(JSON.stringify(telemetryEvent, null, 2));// Approach 1: global crypto (Node.js 19+)
const orderId = crypto.randomUUID();
console.log(orderId);
// "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
// Approach 2: explicit import from node:crypto
import { randomUUID } from 'node:crypto';
const correlationId = randomUUID();
console.log(correlationId);
// "f7e6d5c4-b3a2-4190-8f7e-6d5c4b3a2190"Feature-detecting crypto.randomUUID is worth doing if your code might run in older browsers or embedded WebViews. The check is a single typeof guard:
function generateUUIDv4() {
// Prefer the native API when available
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
// Manual fallback using getRandomValues (see next section)
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
// Set version (4) and variant (RFC 4122)
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10xx
const hex = [...bytes].map(b => b.toString(16).padStart(2, '0'));
return [
hex.slice(0, 4).join(''),
hex.slice(4, 6).join(''),
hex.slice(6, 8).join(''),
hex.slice(8, 10).join(''),
hex.slice(10, 16).join(''),
].join('-');
}
console.log(generateUUIDv4());
// "9b2e4f1a-7c3d-4e8f-a5b6-0d2c1e9f8a7b"crypto.randomUUID() is always available. It throws on non-secure HTTP pages in some browsers. If your application ever runs on plain HTTP during development, the getRandomValues fallback above handles that case.Generate UUID v4 Without a Library
Sometimes you cannot rely on crypto.randomUUID() β maybe you are targeting a WebView that strips the crypto API, or you need to understand what happens under the hood. The manual approach uses crypto.getRandomValues() (available since IE 11) to fill 16 bytes with random data, then applies two bitmask operations to set the version and variant fields. These two operations are the only difference between UUID v4 and a pure random byte string.
function uuidv4Manual() {
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
// Set version: bits 12β15 of byte 6 = 0100 (version 4)
bytes[6] = (bytes[6] & 0x0f) | 0x40;
// Set variant: bits 6β7 of byte 8 = 10 (RFC 4122)
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = [...bytes].map(b => b.toString(16).padStart(2, '0'));
return (
hex.slice(0, 4).join('') + '-' +
hex.slice(4, 6).join('') + '-' +
hex.slice(6, 8).join('') + '-' +
hex.slice(8, 10).join('') + '-' +
hex.slice(10, 16).join('')
);
}
const traceId = uuidv4Manual();
console.log(traceId);
// "e4d7c2a1-3f9b-48e5-a612-9d8c7b6a5f4e"
// Verify it passes UUID v4 validation
const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
console.log(UUID_V4_RE.test(traceId)); // trueMath.random() to generate UUIDs. It is not cryptographically secure, its output period is too short, and some engines produce predictable sequences. Always use crypto.getRandomValues() or crypto.randomUUID().The uuid npm Package β Multi-Version Support
The uuid package on npm has been the go-to UUID library for JavaScript since before crypto.randomUUID() existed. It still makes sense in three situations: you need UUID versions other than v4 (v1, v3, v5, v7), you target runtimes older than Node.js 14.17.0, or you want the validate and parse utility functions. For plain UUID v4 on a modern runtime, the native API is enough and I would skip the dependency.
npm install uuid
import { v4 as uuidv4, validate, version } from 'uuid';
// Generate a UUID v4
const paymentId = uuidv4();
console.log(paymentId);
// "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed"
// Validate any UUID string
console.log(validate(paymentId)); // true
console.log(validate("not-a-uuid")); // false
// Detect the version of a UUID
console.log(version(paymentId)); // 4
// Generate a batch for seeding a test database
const testAccounts = Array.from({ length: 5 }, () => ({
account_id: uuidv4(),
plan: "starter",
created_at: new Date().toISOString(),
}));
console.log(testAccounts);uuid package internally uses crypto.getRandomValues() in browsers and crypto.randomBytes() in Node.js, so the entropy source is identical to the native API. The difference is just the additional utility functions and multi-version support.If you prefer not to write code at all, try the UUID v4 Generator β it generates RFC 4122-compliant v4 identifiers directly in your browser with one click.
Deterministic UUIDs β Generating UUID v5 from a String
UUID v4 is random by definition β calling it twice always gives different results. Sometimes you need the opposite: the same input string should always produce the same UUID. That is what UUID v5 does. It hashes a namespace UUID and an input string with SHA-1, then formats the result as a UUID. Same namespace + same input = same output, every time, on every machine. This is useful for deriving stable IDs from URLs, email addresses, or any string that already identifies a resource.
import { v5 as uuidv5 } from 'uuid';
// Built-in namespace for URLs (RFC 4122)
const URL_NAMESPACE = uuidv5.URL;
// "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
// Same URL always produces the same UUID
const pageId1 = uuidv5("https://api.warehouse.dev/products/sku-7291", URL_NAMESPACE);
const pageId2 = uuidv5("https://api.warehouse.dev/products/sku-7291", URL_NAMESPACE);
console.log(pageId1 === pageId2); // true
console.log(pageId1);
// "a6e4e1c0-7e23-5d3b-8f14-9c2a1b3d5e7f"
// Custom namespace for your application
const APP_NAMESPACE = "f47ac10b-58cc-4372-a567-0e02b2c3d479";
const tenantId = uuidv5("acme-corp", APP_NAMESPACE);
console.log(tenantId);
// "d4735e3a-265b-564e-8f32-7a1b2c3d4e5f"Quick note: UUID v3 does the same thing but with MD5 instead of SHA-1. Prefer v5 for new projects. MD5 has known collision weaknesses, and while that does not matter much for ID generation, there is no reason to choose it over SHA-1 when both are available.
crypto.randomUUID() and Related APIs Reference
The native crypto.randomUUID() takes no arguments β it returns a string and nothing else. Use it when you need RFC 4122 compliant identifiers with zero dependencies. When you need raw random bytes instead of a formatted UUID string β for example, to fill a typed array or derive a key β reach for crypto.getRandomValues() directly. The related APIs that matter for UUID work are listed below.
UUID v4 regex pattern breakdown:
Validate UUID v4 with Regex
Validating that a string is a proper UUID v4 comes up constantly β incoming API request bodies, URL parameters, webhook payloads. A hand-rolled regex is the right choice when you want zero dependencies and are only validating v4. If you are already using the uuid package, prefer its validate() export instead β it handles all UUID versions and is less error-prone than maintaining a custom pattern. The regex /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i checks both the version nibble (must be 4) and the variant nibble (must be 8, 9, a, or b). Use RegExp.prototype.test() for boolean checks and .match() when you need to extract a UUID from surrounding text.
const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
function isUUIDv4(str) {
return UUID_V4_RE.test(str);
}
// Valid UUID v4
console.log(isUUIDv4("9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d")); // true
// UUID v1 β version nibble is 1, not 4
console.log(isUUIDv4("550e8400-e29b-11d4-a716-446655440000")); // false
// UUID v7 β version nibble is 7
console.log(isUUIDv4("018e4a0c-5b3f-7d12-8a9b-0c1d2e3f4a5b")); // false
// Malformed strings
console.log(isUUIDv4("not-a-uuid")); // false
console.log(isUUIDv4("")); // false
console.log(isUUIDv4("9b1deb4d3b7d4bad9bdd2b0d7b3dcb6d")); // false (no hyphens)
// Extract UUID from a larger string
const logLine = 'Request req_id=9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d failed with 503';
const match = logLine.match(/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i);
console.log(match?.[0]);
// "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"Generate and Attach UUIDs from File and API Response
In practice, you rarely call crypto.randomUUID() in isolation. Two patterns come up constantly: assigning IDs to records before writing them to a database, and attaching correlation IDs to outbound API requests so you can trace a request across services in your logs.
Read NDJSON File β Assign UUIDs β Write Back
import { readFileSync, writeFileSync } from 'node:fs';
import { randomUUID } from 'node:crypto';
function assignIds(inputPath, outputPath) {
const lines = readFileSync(inputPath, 'utf-8')
.split('\n')
.filter(line => line.trim());
const records = lines.map(line => {
try {
const record = JSON.parse(line);
if (!record.id) {
record.id = randomUUID();
}
return JSON.stringify(record);
} catch (err) {
console.error(`Skipping malformed line: ${err.message}`);
return null;
}
}).filter(Boolean);
writeFileSync(outputPath, records.join('\n') + '\n');
console.log(`Assigned IDs to ${records.length} records β ${outputPath}`);
}
assignIds('warehouse-products.ndjson', 'warehouse-products-with-ids.ndjson');
// Assigned IDs to 1284 records β warehouse-products-with-ids.ndjsonAttach Correlation ID to Outbound API Request
import { randomUUID } from 'node:crypto';
async function createShipment(orderPayload) {
const correlationId = randomUUID();
try {
const response = await fetch('https://api.logistics.dev/v2/shipments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Correlation-ID': correlationId,
'X-Idempotency-Key': randomUUID(),
},
body: JSON.stringify(orderPayload),
});
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`Shipment API returned ${response.status}: ${errorBody}`);
}
const result = await response.json();
console.log(`Shipment created: ${result.shipment_id} (correlation: ${correlationId})`);
return result;
} catch (err) {
console.error(`[correlation:${correlationId}] Shipment failed: ${err.message}`);
throw err;
}
}
await createShipment({
order_id: "ord_8a3f91bc",
destination: { city: "Portland", state: "OR", zip: "97201" },
items: [{ sku: "WH-7291", quantity: 2, weight_kg: 1.4 }],
});Command-Line UUID Generation
You do not always need a script. Node.js can generate a UUID directly from the command line, which is handy for shell scripts, CI pipelines, and quick ad-hoc testing. The -e flag evaluates a single expression.
# Single UUID node -e "console.log(crypto.randomUUID())" # 3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f # Five UUIDs at once node -e "for(let i=0;i<5;i++) console.log(crypto.randomUUID())" # Generate and assign to a shell variable export REQUEST_ID=$(node -e "process.stdout.write(crypto.randomUUID())") echo "Request ID: $REQUEST_ID" # Use npx uuid (if you have the package installed globally or want a one-off) npx uuid v4 # 1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed
# Open any browser DevTools console and type: crypto.randomUUID() # "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
uuidgen is pre-installed on macOS and most Linux distributions. It generates UUID v4 by default on modern systems.High-Performance Alternative β nanoid
If you are generating thousands of IDs per second and the 36-character UUID format is not a hard requirement, consider nanoid. It is 2x faster than uuid.v4(), produces a 21-character URL-safe ID by default, and weighs about 1 KB after minification. The output is not a UUID β it is a custom-alphabet ID β so do not use it where RFC 4122 compliance is required (database UUID columns, APIs that validate UUID format, OpenTelemetry trace IDs). But for internal correlation IDs, React component keys, and URL slugs, it is a good fit.
npm install nanoid
import { nanoid, customAlphabet } from 'nanoid';
// Default: 21-char URL-safe ID (A-Za-z0-9_-)
const trackingCode = nanoid();
console.log(trackingCode);
// "V1StGXR8_Z5jdHi6B-myT"
// Custom length
const shortCode = nanoid(10);
console.log(shortCode);
// "IRFa-VaY2b"
// Custom alphabet β numbers only, 12 digits
const numericId = customAlphabet('0123456789', 12);
console.log(numericId());
// "839274651023"
// Custom alphabet β hex only, 32 chars (same entropy as UUID v4 without hyphens)
const hexId = customAlphabet('0123456789abcdef', 32);
console.log(hexId());
// "4f8a1b2c3d7e9f0a5b6c8d1e2f3a4b5c"Terminal Output with Syntax Highlighting
Debugging UUID-heavy applications means staring at walls of hex strings in the terminal. Color-coding helps. The chalk library (or the newer built-in node:util styleText in Node.js 21.7+) lets you highlight UUIDs in log output so they stand out from surrounding text.
import chalk from 'chalk';
import { randomUUID } from 'node:crypto';
function logEvent(action, metadata = {}) {
const eventId = randomUUID();
const timestamp = new Date().toISOString();
console.log(
chalk.gray(timestamp),
chalk.cyan(eventId),
chalk.white(action),
Object.keys(metadata).length
? chalk.dim(JSON.stringify(metadata))
: ''
);
}
logEvent('shipment.created', { order_id: 'ord_8a3f', carrier: 'fedex' });
logEvent('payment.captured', { amount_cents: 14999, currency: 'USD' });
logEvent('webhook.delivered', { endpoint: 'https://hooks.acme.dev/orders' });
// 2026-03-27T10:15:00.000Z a1b2c3d4-... shipment.created {"order_id":"ord_8a3f",...}Generate Short Unique IDs in JavaScript
A 36-character UUID is sometimes too long β URL slugs, QR code data, SMS messages, and embedded hardware protocols all have length constraints.
import { randomUUID } from 'node:crypto';
// 1. Strip hyphens from UUID v4 β 32-char hex string
const hex32 = randomUUID().replaceAll('-', '');
console.log(hex32);
// "3e7f1a924b0c4d8e9f127a6b3c8d5e1f" (32 chars)
// 2. Base64-encode 16 random bytes β 22-char string (URL-safe)
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
const base64Id = Buffer.from(bytes)
.toString('base64url')
.replace(/=+$/, '');
console.log(base64Id);
// "Pj8akksNTY6fEnarPIvR" (22 chars, 128 bits of entropy)
// 3. nanoid at custom length
import { nanoid } from 'nanoid';
const short12 = nanoid(12);
console.log(short12);
// "V1StGXR8_Z5j" (12 chars, ~71 bits of entropy)The collision probability math: a 12-character nanoid (default alphabet of 64 characters) gives roughly 71 bits of entropy. At 1,000 IDs per second, you would need about 116 years to reach a 1% collision probability. For most applications, that is more than enough. If you are generating millions of IDs per day, stick with the full UUID or use nanoid with at least 21 characters.
UUID v7 β Time-Ordered Alternative to v4
UUID v7 (defined in RFC 9562) embeds a 48-bit Unix millisecond timestamp in the first segment, followed by random bits. The result is a UUID that looks similar to v4 but sorts chronologically. This makes it a better choice than v4 for database primary keys: new rows always land at the end of the B-tree index instead of at random positions, which reduces page splits and fragmentation. In projects where I need time-ordered IDs for a Postgres table, I switch to v7 immediately β the index performance difference is measurable at scale. The UUID v7 Generator on ToolDeck shows the embedded timestamp for any v7 UUID.
import { v7 as uuidv7 } from 'uuid';
// Generate three UUID v7 values β notice they sort chronologically
const id1 = uuidv7();
const id2 = uuidv7();
const id3 = uuidv7();
console.log(id1);
// "018e4a0c-5b3f-7d12-8a9b-0c1d2e3f4a5b"
console.log(id2);
// "018e4a0c-5b40-7e34-9c2d-1e4f5a6b7c8d"
console.log(id3);
// "018e4a0c-5b41-7f56-ae3f-2a5b6c7d8e9f"
// They sort lexicographically by creation time
console.log([id3, id1, id2].sort());
// [id1, id2, id3] β chronological order preserved
// Use v4 for tokens where timing should not be leaked
import { v4 as uuidv4 } from 'uuid';
const sessionToken = uuidv4(); // fully random, no timing infouuid package supports v7 from version 9.0.0 onwards. If you are on an older version, run npm install uuid@latest to upgrade.UUID v4 in the Browser Without a Build Step
No bundler, no npm, no transpiler. Just a plain HTML file. This is the simplest possible way to generate a UUID in client-side JavaScript. It works because crypto.randomUUID() is a built-in browser API.
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>UUID Generator</title></head>
<body>
<p>Your UUID: <strong id="output"></strong></p>
<button onclick="document.getElementById('output').textContent = crypto.randomUUID()">
Generate
</button>
<script>
// Generate one on page load
document.getElementById('output').textContent = crypto.randomUUID();
</script>
</body>
</html>That is the entire file. No CDN imports, no script tags pulling in libraries. For anything more complex β batch generation, validation, deterministic IDs β you will want the uuid package or the manual fallback shown earlier. But for a quick prototype or internal tool, this is all you need.
Common Mistakes
I've seen the Math.random() UUID pattern copied from old blog posts into production code more often than I'd like to admit. The bugs these patterns introduce are silent: no runtime error, just subtly wrong behavior that surfaces later under load or in security reviews.
Problem: Math.random() is not cryptographically secure. Its output is predictable in some engines, and the low entropy makes collisions far more likely than a proper CSPRNG.
Fix: Always use crypto.randomUUID() or crypto.getRandomValues(). Both use the operating system's CSPRNG.
// INSECURE β predictable, low entropy
function badUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
/[xy]/g,
c => {
const r = Math.random() * 16 | 0;
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
}
);
}// SECURE β uses the OS CSPRNG
const id = crypto.randomUUID();
// Or if you need a manual fallback:
function secureUuid() {
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const h = [...bytes].map(b => b.toString(16).padStart(2, '0'));
return `${h.slice(0,4).join('')}-${h.slice(4,6).join('')}-${h.slice(6,8).join('')}-${h.slice(8,10).join('')}-${h.slice(10).join('')}`;
}Problem: crypto.randomUUID() returns lowercase hex, but UUIDs from other systems (databases, APIs, user input) might use uppercase. Direct === comparison fails when cases differ.
Fix: Normalize both sides to lowercase before comparing.
const fromApi = "9B1DEB4D-3B7D-4BAD-9BDD-2B0D7B3DCB6D"; // uppercase from API
const local = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"; // lowercase from crypto
if (fromApi === local) { /* never runs */ }const fromApi = "9B1DEB4D-3B7D-4BAD-9BDD-2B0D7B3DCB6D";
const local = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d";
if (fromApi.toLowerCase() === local.toLowerCase()) {
// matches correctly
}Problem: Some UUID libraries (especially in other languages) return UUID objects. In JavaScript, accidentally wrapping a UUID string in an object breaks equality checks, JSON serialization, and database queries.
Fix: Always store and pass UUIDs as plain strings. If a library returns an object, call .toString() or access the string property immediately.
// Creating unnecessary wrapper
class UUID {
constructor(value) { this.value = value; }
}
const id = new UUID(crypto.randomUUID());
console.log(id === id); // true, but...
console.log(JSON.stringify({ id })); // {"id":{"value":"..."}}// Just use a string
const id = crypto.randomUUID();
console.log(JSON.stringify({ id }));
// {"id":"3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"}Problem: UUID v4 is fully random. Sorting by UUID v4 gives arbitrary order, not creation order. This leads to unpredictable pagination, confusing admin UIs, and bad database index performance.
Fix: Use UUID v7 when you need time-ordered identifiers. Keep UUID v4 for tokens and correlation IDs where sort order is irrelevant.
// Bad: using v4 as a sortable primary key
const rows = [
{ id: crypto.randomUUID(), created: "2026-03-27" },
{ id: crypto.randomUUID(), created: "2026-03-26" },
];
rows.sort((a, b) => a.id.localeCompare(b.id));
// Sort order is random β NOT by creation dateimport { v7 as uuidv7 } from 'uuid';
// Good: v7 sorts by creation time
const rows = [
{ id: uuidv7(), created: "2026-03-27" },
{ id: uuidv7(), created: "2026-03-26" },
];
rows.sort((a, b) => a.id.localeCompare(b.id));
// Sort order matches creation timecrypto.randomUUID() vs uuid vs nanoid β Quick Comparison
For most JavaScript projects: use crypto.randomUUID() when you only need UUID v4 and your runtime is recent enough. Reach for the uuid package when you need v5 (deterministic) or v7 (time-ordered) support. Use nanoid when a short, URL-safe ID is more practical than a 36-character UUID β but remember that nanoid output is not UUID-compliant and will fail validation on any system expecting RFC 4122 format.
For a no-code alternative, try the UUID v4 Generator to create identifiers instantly in the browser. To inspect an existing UUID, paste it into the UUID Decoder to see its version, variant, and any embedded timestamp data.
Frequently Asked Questions
How do I generate a UUID v4 in JavaScript?
Call crypto.randomUUID() in any modern browser (Chrome 92+, Firefox 95+, Safari 15.4+) or Node.js 19+. It returns a lowercase string like "3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f". No import is needed in browsers because crypto is a built-in global; in Node.js you can also use import { randomUUID } from "node:crypto" to be explicit about the module. For runtimes older than Node.js 19 you can still call crypto.randomUUID() on the global β it was available experimentally from Node.js 14.17.0. If you need a no-code option, the UUID v4 Generator at /en/uuid/v4 produces compliant identifiers in one click.
const sessionId = crypto.randomUUID(); console.log(sessionId); // "3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"
Is crypto.randomUUID() cryptographically secure?
Yes. crypto.randomUUID() uses the same CSPRNG (cryptographically secure pseudorandom number generator) that backs crypto.getRandomValues(). The 122 random bits in a UUID v4 make collision probability negligible for all practical purposes β you would need to generate roughly 2.71 quintillion UUIDs before reaching a 50% chance of a single collision. The entropy comes from the operating system's random source (/dev/urandom on Linux, BCryptGenRandom on Windows), not from Math.random(), which is explicitly not cryptographically secure. This means UUID v4 values are safe to use as session tokens, CSRF tokens, and other security-sensitive identifiers where predictability must be avoided. Never substitute Math.random()-based UUID generators in security contexts.
Can I use UUID v4 as a database primary key?
You can, but there is a meaningful performance trade-off. UUID v4 is fully random, so B-tree indexes fragment badly because each new row inserts at a random position in the index rather than at the end. On write-heavy tables this causes excessive page splits and cache misses, which degrades INSERT and range-scan performance. If your database supports it (PostgreSQL, MySQL 8.0+, SQL Server), UUID v7 (time-ordered) is a better primary key because new rows always append near the end of the index. UUID v4 remains the right choice for session tokens, OAuth state parameters, idempotency keys, correlation IDs, and any field where hiding creation time is desirable.
// UUID v4 β random, not sortable
const correlationId = crypto.randomUUID();
// UUID v7 β time-ordered, better for DB primary keys
import { v7 as uuidv7 } from 'uuid';
const rowId = uuidv7();What is the difference between UUID v4 and UUID v7?
UUID v4 fills 122 bits with random data β every segment is effectively noise. UUID v7 (RFC 9562, published 2024) encodes a 48-bit Unix millisecond timestamp in the first segment, 12 bits of sub-millisecond precision in the second segment, and random bits in the remainder. Both are 128 bits total and use the same 36-character hyphenated format, so they are interchangeable at the storage layer. UUID v7 is lexicographically sortable by creation time, which keeps B-tree indexes compact and makes range queries on time windows efficient. Choose UUID v4 when the ID must not reveal when it was created β for example, public-facing tokens where timing information could be exploited β and UUID v7 for database primary keys, audit logs, and event streams where chronological order matters.
How do I validate a UUID v4 string in JavaScript?
Test against the regex /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i. The literal "4" in position 15 (0-indexed) confirms the version nibble; the character at position 20 β one of 8, 9, a, or b β encodes the RFC 4122 variant bits. This regex correctly rejects UUID v1, v7, and any malformed string. The i flag makes it case-insensitive, so uppercase hex digits from other systems pass validation without normalization. If you only need to know whether a string is any valid UUID (regardless of version), use the looser pattern /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i instead.
const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
UUID_V4_RE.test("550e8400-e29b-41d4-a716-446655440000"); // true
UUID_V4_RE.test("550e8400-e29b-11d4-a716-446655440000"); // false (v1)
UUID_V4_RE.test("not-a-uuid"); // falseHow do I generate a short unique ID in JavaScript?
Strip hyphens from a UUID v4 to get a 32-character hex string: crypto.randomUUID().replaceAll("-", ""). For something even shorter, use nanoid which produces a 21-character URL-safe ID (AβZ, aβz, 0β9, _ and -) by default with comparable collision resistance to a full UUID. The trade-off is straightforward: shorter IDs have higher collision probability, but nanoid at 21 characters still provides 126 bits of entropy, which is more than sufficient for virtually every real-world application. For URL slugs and QR code payloads you can go as short as 10β12 characters with nanoid before collision probability becomes a concern at typical generation rates. Avoid Base64-encoding a raw UUID and truncating it β truncation destroys the statistical independence of the bits and makes collisions harder to reason about.
// 32-char hex string from UUID v4
const hexId = crypto.randomUUID().replaceAll('-', '');
// "3e7f1a924b0c4d8e9f127a6b3c8d5e1f"
// 21-char URL-safe ID via nanoid
import { nanoid } from 'nanoid';
const shortId = nanoid();
// "V1StGXR8_Z5jdHi6B-myT"Related Tools
Sophie is a full-stack developer focused on TypeScript across the entire stack β from React frontends to Express and Fastify backends. She has a particular interest in type-safe API design, runtime validation, and the patterns that make large JavaScript codebases stay manageable. She writes about TypeScript idioms, Node.js internals, and the ever-evolving JavaScript module ecosystem.
Marcus specialises in JavaScript performance, build tooling, and the inner workings of the V8 engine. He has spent years profiling and optimising React applications, working on bundler configurations, and squeezing every millisecond out of critical rendering paths. He writes about Core Web Vitals, JavaScript memory management, and the tools developers reach for when performance really matters.