Tạo UUID v4 trong JavaScript — Hướng dẫn
Sử dụng Trình tạo UUID v4 miễn phí trực tiếp trên trình duyệt — không cần cài đặt.
Dùng thử Trình tạo UUID v4 trực tuyến →Mọi ứng dụng JavaScript đều cần định danh duy nhất — session token, hàng database, idempotency key cho payment API, correlation ID cho distributed tracing. Cách đơn giản nhất để tạo UUID v4 trong JavaScript hiện nay là crypto.randomUUID(): không phụ thuộc, một dòng lệnh, an toàn về mật mã. UUID v4 được sử dụng rộng rãi chính xác vì nó không cần phối hợp giữa các dịch vụ — client và server đều có thể tạo ID
độc lập mà không lo va chạm. Hướng dẫn này bao gồm API tích hợp sẵn đó, gói uuid npm, xác thực — tất cả trên Node.js 19+ và trình duyệt hiện đại. Nếu cần tùy chọn không code, UUID v4 Generator trên ToolDeck tạo ra định danh hợp lệ ngay lập tức.
- ✓crypto.randomUUID() được tích hợp sẵn trong trình duyệt và Node.js — không phụ thuộc, một dòng code.
- ✓UUID v4 là định danh ngẫu nhiên 128 bit: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx (y là 8, 9, a, hoặc b).
- ✓Xác thực với /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i — kiểm tra bit phiên bản và biến thể.
- ✓Gói uuid npm thêm hỗ trợ v1, v3, v5 và v7 khi bạn cần nhiều hơn ID ngẫu nhiên.
- ✓Với khóa chính database, ưu tiên UUID v7 (có thứ tự thời gian) hơn v4 (ngẫu nhiên) để giảm phân mảnh index.
UUID v4 là gì?
UUID (Universally Unique Identifier) phiên bản 4 là định danh ngẫu nhiên 128 bit được định dạng thành 32 chữ số hexadecimal phân cách bởi bốn dấu gạch ngang: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx. Chữ 4 ở vị trí 15 đánh dấu phiên bản. Ký tự y ở vị trí 20 là một trong 8, 9, a, hoặc b (biến thể RFC 4122). 122 bit còn lại là ngẫu nhiên. UUID v4 là phiên bản phổ biến nhất trong ứng dụng JavaScript vì nó không cần phối hợp giữa các hệ thống — bạn có thể tạo ID độc lập trên client và server mà không lo va chạm.
// Không có định danh
const event = { action: "user.login", ts: 1711824000 };// Với UUID v4
const event = {
id: "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
action: "user.login",
ts: 1711824000
};crypto.randomUUID() — Cách tiếp cận JavaScript gốc
crypto.randomUUID() có sẵn trong Chrome 92+, Firefox 95+, Safari 15.4+, và Node.js 19+ (với hỗ trợ thử nghiệm từ Node.js 14.17.0 thông qua globalThis.crypto). Nó trả về chuỗi UUID v4 36 ký tự chữ thường. Không cần import trong JavaScript trình duyệt. Trong Node.js, bạn có thể gọi trực tiếp trên đối tượng crypto toàn cục hoặc import rõ ràng từ module node:crypto.
// Hoạt động trong mọi trình duyệt hiện đại — không cần build step, không bundler
const requestId = crypto.randomUUID();
console.log(requestId);
// "3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"
// Dùng ở bất cứ đâu cần định danh duy nhất
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));// Cách 1: crypto toàn cục (Node.js 19+)
const orderId = crypto.randomUUID();
console.log(orderId);
// "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
// Cách 2: import rõ ràng từ node:crypto
import { randomUUID } from 'node:crypto';
const correlationId = randomUUID();
console.log(correlationId);
// "f7e6d5c4-b3a2-4190-8f7e-6d5c4b3a2190"Nên phát hiện tính năng crypto.randomUUID nếu code của bạn có thể chạy trên trình duyệt cũ hoặc WebView nhúng. Kiểm tra chỉ là một guard typeof đơn giản:
function generateUUIDv4() {
// Ưu tiên API gốc khi có sẵn
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
// Fallback thủ công dùng getRandomValues (xem phần tiếp theo)
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
// Đặt version (4) và 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() luôn có sẵn. Nó throw trên các trang HTTP không bảo mật trong một số trình duyệt. Nếu ứng dụng của bạn đôi khi chạy trên HTTP thuần trong quá trình phát triển, fallback getRandomValues ở trên xử lý trường hợp đó.Tạo UUID v4 không cần thư viện
Đôi khi bạn không thể dựa vào crypto.randomUUID() — có thể bạn đang nhắm đến WebView không có API crypto, hoặc bạn muốn hiểu những gì xảy ra bên dưới. Cách thủ công dùng crypto.getRandomValues() (có sẵn từ IE 11) để điền 16 byte với dữ liệu ngẫu nhiên, sau đó áp dụng hai phép bitmask để đặt trường version và variant. Hai phép toán này là sự khác biệt duy nhất giữa UUID v4 và chuỗi byte ngẫu nhiên thuần túy.
function uuidv4Manual() {
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
// Đặt version: các bit 12–15 của byte 6 = 0100 (version 4)
bytes[6] = (bytes[6] & 0x0f) | 0x40;
// Đặt variant: các bit 6–7 của 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"
// Xác minh nó qua xác thực UUID v4
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() để tạo UUID. Nó không an toàn về mật mã, chu kỳ đầu ra quá ngắn, và một số engine tạo ra chuỗi có thể dự đoán được. Luôn dùng crypto.getRandomValues() hoặc crypto.randomUUID().Gói uuid npm — Hỗ trợ nhiều phiên bản
Gói uuid trên npm đã là thư viện UUID go-to cho JavaScript trước khi crypto.randomUUID() tồn tại. Nó vẫn hợp lý trong ba tình huống: bạn cần phiên bản UUID khác ngoài v4 (v1, v3, v5, v7), bạn nhắm đến runtime cũ hơn Node.js 14.17.0, hoặc bạn muốn các hàm tiện ích validate và parse. Với UUID v4 thuần trên runtime hiện đại, API gốc là đủ và tôi sẽ bỏ qua dependency này.
npm install uuid
import { v4 as uuidv4, validate, version } from 'uuid';
// Tạo UUID v4
const paymentId = uuidv4();
console.log(paymentId);
// "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed"
// Xác thực bất kỳ chuỗi UUID nào
console.log(validate(paymentId)); // true
console.log(validate("not-a-uuid")); // false
// Phát hiện phiên bản của UUID
console.log(version(paymentId)); // 4
// Tạo hàng loạt để seed database test
const testAccounts = Array.from({ length: 5 }, () => ({
account_id: uuidv4(),
plan: "starter",
created_at: new Date().toISOString(),
}));
console.log(testAccounts);uuid nội bộ dùng crypto.getRandomValues() trong trình duyệt và crypto.randomBytes() trong Node.js, nên nguồn entropy giống hệt API gốc. Sự khác biệt chỉ là các hàm tiện ích bổ sung và hỗ trợ nhiều phiên bản.Nếu bạn không muốn viết code chút nào, hãy thử UUID v4 Generator — nó tạo ra định danh v4 tuân thủ RFC 4122 ngay trong trình duyệt với một cú nhấp.
UUID tất định — Tạo UUID v5 từ một chuỗi
UUID v4 ngẫu nhiên theo định nghĩa — gọi hai lần luôn cho kết quả khác nhau. Đôi khi bạn cần điều ngược lại: cùng một chuỗi đầu vào luôn tạo ra cùng một UUID. Đó là điều UUID v5 làm. Nó hash một namespace UUID và chuỗi đầu vào với SHA-1, rồi định dạng kết quả thành UUID. Cùng namespace + cùng đầu vào = cùng đầu ra, mọi lúc, trên mọi máy. Điều này hữu ích cho việc suy ra ID ổn định từ URL, địa chỉ email, hoặc bất kỳ chuỗi nào đã xác định một tài nguyên.
import { v5 as uuidv5 } from 'uuid';
// Namespace tích hợp cho URL (RFC 4122)
const URL_NAMESPACE = uuidv5.URL;
// "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
// Cùng URL luôn tạo ra cùng 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"
// Namespace tùy chỉnh cho ứng dụng của bạn
const APP_NAMESPACE = "f47ac10b-58cc-4372-a567-0e02b2c3d479";
const tenantId = uuidv5("acme-corp", APP_NAMESPACE);
console.log(tenantId);
// "d4735e3a-265b-564e-8f32-7a1b2c3d4e5f"Ghi chú nhanh: UUID v3 làm điều tương tự nhưng với MD5 thay vì SHA-1. Ưu tiên v5 cho các dự án mới. MD5 có các điểm yếu va chạm đã biết, và mặc dù điều đó không quá quan trọng cho việc tạo ID, không có lý do gì để chọn nó khi cả hai đều có sẵn.
Tham chiếu crypto.randomUUID() và các API liên quan
API gốc crypto.randomUUID() không nhận tham số — nó trả về một chuỗi và không gì khác. Dùng khi bạn cần định danh tuân thủ RFC 4122 với không phụ thuộc. Khi bạn cần các byte ngẫu nhiên thô thay vì chuỗi UUID đã định dạng — ví dụ, để điền typed array hoặc suy ra khóa — hãy dùng crypto.getRandomValues() trực tiếp. Các API liên quan quan trọng cho công việc UUID được liệt kê dưới đây.
Phân tích mẫu regex UUID v4:
Xác thực UUID v4 với Regex
Xác thực rằng một chuỗi là UUID v4 đúng đắn xuất hiện liên tục — body request API đến, tham số URL, webhook payload. Regex tự viết là lựa chọn đúng khi bạn muốn không phụ thuộc và chỉ xác thực v4. Nếu bạn đã dùng gói uuid, hãy ưu tiên hàm validate() của nó — nó xử lý tất cả phiên bản UUID và ít dễ mắc lỗi hơn so với việc duy trì mẫu tùy chỉnh. Regex /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i kiểm tra cả nibble phiên bản (phải là 4) và nibble biến thể (phải là 8, 9, a, hoặc b). Dùng RegExp.prototype.test() cho kiểm tra boolean và .match() khi bạn cần trích xuất UUID từ văn bản xung quanh.
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);
}
// UUID v4 hợp lệ
console.log(isUUIDv4("9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d")); // true
// UUID v1 — nibble phiên bản là 1, không phải 4
console.log(isUUIDv4("550e8400-e29b-11d4-a716-446655440000")); // false
// UUID v7 — nibble phiên bản là 7
console.log(isUUIDv4("018e4a0c-5b3f-7d12-8a9b-0c1d2e3f4a5b")); // false
// Chuỗi sai định dạng
console.log(isUUIDv4("not-a-uuid")); // false
console.log(isUUIDv4("")); // false
console.log(isUUIDv4("9b1deb4d3b7d4bad9bdd2b0d7b3dcb6d")); // false (không có dấu gạch ngang)
// Trích xuất UUID từ chuỗi lớn hơn
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"Tạo và gắn UUID từ File và API Response
Trong thực tế, bạn hiếm khi gọi crypto.randomUUID() đơn độc. Hai mẫu xuất hiện liên tục: gán ID cho bản ghi trước khi ghi vào database, và gắn correlation ID vào outbound API request để bạn có thể truy vết một request qua các dịch vụ trong log.
Đọc file NDJSON → Gán UUID → Ghi lại
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(`Bỏ qua dòng lỗi: ${err.message}`);
return null;
}
}).filter(Boolean);
writeFileSync(outputPath, records.join('\n') + '\n');
console.log(`Đã gán ID cho ${records.length} bản ghi → ${outputPath}`);
}
assignIds('warehouse-products.ndjson', 'warehouse-products-with-ids.ndjson');
// Đã gán ID cho 1284 bản ghi → warehouse-products-with-ids.ndjsonGắn Correlation ID vào 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 trả về ${response.status}: ${errorBody}`);
}
const result = await response.json();
console.log(`Đã tạo shipment: ${result.shipment_id} (correlation: ${correlationId})`);
return result;
} catch (err) {
console.error(`[correlation:${correlationId}] Shipment thất bại: ${err.message}`);
throw err;
}
}
await createShipment({
order_id: "ord_8a3f91bc",
destination: { city: "Hà Nội", state: "HN", zip: "10000" },
items: [{ sku: "WH-7291", quantity: 2, weight_kg: 1.4 }],
});Tạo UUID từ dòng lệnh
Bạn không phải lúc nào cũng cần script. Node.js có thể tạo UUID trực tiếp từ dòng lệnh, rất tiện cho shell script, CI pipeline và kiểm thử ad-hoc nhanh. Flag -e đánh giá một biểu thức đơn.
# UUID đơn lẻ node -e "console.log(crypto.randomUUID())" # 3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f # Năm UUID cùng lúc node -e "for(let i=0;i<5;i++) console.log(crypto.randomUUID())" # Tạo và gán vào biến shell export REQUEST_ID=$(node -e "process.stdout.write(crypto.randomUUID())") echo "Request ID: $REQUEST_ID" # Dùng npx uuid (nếu đã cài gói toàn cục hoặc muốn dùng một lần) npx uuid v4 # 1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed
# Mở DevTools console của bất kỳ trình duyệt nào và gõ: crypto.randomUUID() # "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
uuidgen được cài sẵn trên macOS và hầu hết bản phân phối Linux. Nó tạo UUID v4 theo mặc định trên các hệ thống hiện đại.Thay thế hiệu năng cao — nanoid
Nếu bạn đang tạo hàng nghìn ID mỗi giây và định dạng UUID 36 ký tự không phải yêu cầu cứng, hãy xem xét nanoid. Nó nhanh gấp 2x so với uuid.v4(), tạo ra ID URL-safe 21 ký tự theo mặc định, và nặng khoảng 1 KB sau khi minify. Đầu ra không phải UUID — nó là ID alphabet tùy chỉnh — nên đừng dùng khi cần tuân thủ RFC 4122 (cột UUID database, API xác thực định dạng UUID, OpenTelemetry trace ID). Nhưng cho correlation ID nội bộ, React component key và URL slug, nó là lựa chọn tốt.
npm install nanoid
import { nanoid, customAlphabet } from 'nanoid';
// Mặc định: ID URL-safe 21 ký tự (A-Za-z0-9_-)
const trackingCode = nanoid();
console.log(trackingCode);
// "V1StGXR8_Z5jdHi6B-myT"
// Độ dài tùy chỉnh
const shortCode = nanoid(10);
console.log(shortCode);
// "IRFa-VaY2b"
// Alphabet tùy chỉnh — chỉ số, 12 chữ số
const numericId = customAlphabet('0123456789', 12);
console.log(numericId());
// "839274651023"
// Alphabet tùy chỉnh — chỉ hex, 32 ký tự (entropy tương đương UUID v4 không có dấu gạch ngang)
const hexId = customAlphabet('0123456789abcdef', 32);
console.log(hexId());
// "4f8a1b2c3d7e9f0a5b6c8d1e2f3a4b5c"Đầu ra Terminal với tô màu cú pháp
Debug ứng dụng nặng UUID nghĩa là nhìn chằm chằm vào những bức tường chuỗi hex trong terminal. Tô màu giúp ích. Thư viện chalk (hoặc node:util styleText mới hơn có sẵn trong Node.js 21.7+) cho phép bạn làm nổi bật UUID trong log để chúng nổi bật so với văn bản xung quanh.
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",...}Tạo ID duy nhất ngắn trong JavaScript
UUID 36 ký tự đôi khi quá dài — URL slug, dữ liệu QR code, tin nhắn SMS và giao thức phần cứng nhúng đều có giới hạn độ dài.
import { randomUUID } from 'node:crypto';
// 1. Bỏ dấu gạch ngang từ UUID v4 → chuỗi hex 32 ký tự
const hex32 = randomUUID().replaceAll('-', '');
console.log(hex32);
// "3e7f1a924b0c4d8e9f127a6b3c8d5e1f" (32 ký tự)
// 2. Base64-encode 16 byte ngẫu nhiên → chuỗi 22 ký tự (URL-safe)
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
const base64Id = Buffer.from(bytes)
.toString('base64url')
.replace(/=+$/, '');
console.log(base64Id);
// "Pj8akksNTY6fEnarPIvR" (22 ký tự, 128 bit entropy)
// 3. nanoid với độ dài tùy chỉnh
import { nanoid } from 'nanoid';
const short12 = nanoid(12);
console.log(short12);
// "V1StGXR8_Z5j" (12 ký tự, ~71 bit entropy)Tính toán xác suất va chạm: nanoid 12 ký tự (alphabet mặc định 64 ký tự) cung cấp khoảng 71 bit entropy. Ở tốc độ 1.000 ID mỗi giây, bạn cần khoảng 116 năm để đạt xác suất va chạm 1%. Với hầu hết ứng dụng, đó là đủ rồi. Nếu bạn đang tạo hàng triệu ID mỗi ngày, hãy giữ UUID đầy đủ hoặc dùng nanoid với ít nhất 21 ký tự.
UUID v7 — Thay thế có thứ tự thời gian cho v4
UUID v7 (định nghĩa trong RFC 9562) nhúng timestamp Unix millisecond 48 bit vào đoạn đầu tiên, theo sau là các bit ngẫu nhiên. Kết quả là UUID trông giống v4 nhưng sắp xếp theo thời gian. Điều này làm cho nó là lựa chọn tốt hơn v4 cho khóa chính database: các hàng mới luôn đến cuối index B-tree thay vì tại vị trí ngẫu nhiên, điều này giảm page split và phân mảnh. Trong các dự án cần ID có thứ tự thời gian cho bảng Postgres, tôi chuyển sang v7 ngay — sự khác biệt hiệu năng index rõ ràng ở quy mô lớn. UUID v7 Generator trên ToolDeck hiển thị timestamp nhúng cho bất kỳ UUID v7 nào.
import { v7 as uuidv7 } from 'uuid';
// Tạo ba giá trị UUID v7 — lưu ý chúng sắp xếp theo thời gian
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"
// Chúng sắp xếp từ điển theo thời gian tạo
console.log([id3, id1, id2].sort());
// [id1, id2, id3] — thứ tự thời gian được bảo toàn
// Dùng v4 cho token khi không muốn lộ thời gian
import { v4 as uuidv4 } from 'uuid';
const sessionToken = uuidv4(); // hoàn toàn ngẫu nhiên, không có thông tin thời gianuuid hỗ trợ v7 từ phiên bản 9.0.0 trở lên. Nếu bạn đang dùng phiên bản cũ hơn, chạy npm install uuid@latest để nâng cấp.UUID v4 trong trình duyệt không cần Build Step
Không bundler, không npm, không transpiler. Chỉ một file HTML thuần. Đây là cách đơn giản nhất có thể để tạo UUID trong JavaScript phía client. Nó hoạt động vì crypto.randomUUID() là API trình duyệt tích hợp sẵn.
<!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>
// Tạo một UUID khi tải trang
document.getElementById('output').textContent = crypto.randomUUID();
</script>
</body>
</html>Đó là toàn bộ file. Không có CDN import, không có script tag kéo thư viện. Cho những thứ phức tạp hơn — tạo hàng loạt, xác thực, ID tất định — bạn sẽ muốn gói uuid hoặc fallback thủ công đã hiển thị ở trên. Nhưng cho prototype nhanh hoặc công cụ nội bộ, đây là tất cả những gì bạn cần.
Lỗi thường gặp
Tôi đã thấy mẫu UUID dùng Math.random() được sao chép từ các bài blog cũ vào code production thường xuyên hơn tôi muốn thừa nhận. Các lỗi mà những mẫu này gây ra là âm thầm: không có lỗi runtime, chỉ là hành vi sai tinh tế xuất hiện sau dưới tải hoặc trong quá trình review bảo mật.
Vấn đề: Math.random() không an toàn về mật mã. Đầu ra của nó có thể dự đoán được trong một số engine, và entropy thấp làm cho va chạm xảy ra thường xuyên hơn nhiều so với CSPRNG đúng đắn.
Giải pháp: Luôn dùng crypto.randomUUID() hoặc crypto.getRandomValues(). Cả hai đều dùng CSPRNG của hệ điều hành.
// KHÔNG AN TOÀN — có thể dự đoán, entropy thấp
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);
}
);
}// AN TOÀN — dùng CSPRNG của OS
const id = crypto.randomUUID();
// Hoặc nếu bạn cần fallback thủ công:
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('')}`;
}Vấn đề: crypto.randomUUID() trả về hex chữ thường, nhưng UUID từ các hệ thống khác (database, API, user input) có thể dùng chữ hoa. So sánh === trực tiếp thất bại khi case khác nhau.
Giải pháp: Chuẩn hóa cả hai phía thành chữ thường trước khi so sánh.
const fromApi = "9B1DEB4D-3B7D-4BAD-9BDD-2B0D7B3DCB6D"; // chữ hoa từ API
const local = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"; // chữ thường từ crypto
if (fromApi === local) { /* không bao giờ chạy */ }const fromApi = "9B1DEB4D-3B7D-4BAD-9BDD-2B0D7B3DCB6D";
const local = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d";
if (fromApi.toLowerCase() === local.toLowerCase()) {
// khớp đúng
}Vấn đề: Một số thư viện UUID (đặc biệt trong các ngôn ngữ khác) trả về UUID object. Trong JavaScript, vô tình bọc chuỗi UUID trong object phá vỡ kiểm tra bằng nhau, JSON serialization và database query.
Giải pháp: Luôn lưu và truyền UUID dưới dạng chuỗi thuần. Nếu thư viện trả về object, gọi .toString() hoặc truy cập thuộc tính chuỗi ngay lập tức.
// Tạo wrapper không cần thiết
class UUID {
constructor(value) { this.value = value; }
}
const id = new UUID(crypto.randomUUID());
console.log(id === id); // true, nhưng...
console.log(JSON.stringify({ id })); // {"id":{"value":"..."}}// Chỉ cần dùng string
const id = crypto.randomUUID();
console.log(JSON.stringify({ id }));
// {"id":"3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"}Vấn đề: UUID v4 hoàn toàn ngẫu nhiên. Sắp xếp theo UUID v4 cho thứ tự tùy tiện, không phải thứ tự tạo. Điều này dẫn đến phân trang không thể dự đoán, UI admin khó hiểu, và hiệu năng index database kém.
Giải pháp: Dùng UUID v7 khi bạn cần định danh có thứ tự thời gian. Giữ UUID v4 cho token và correlation ID nơi thứ tự sắp xếp không liên quan.
// Xấu: dùng v4 làm khóa chính có thể sắp xếp
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));
// Thứ tự sắp xếp là ngẫu nhiên — KHÔNG theo ngày tạoimport { v7 as uuidv7 } from 'uuid';
// Tốt: v7 sắp xếp theo thời gian tạo
const rows = [
{ id: uuidv7(), created: "2026-03-27" },
{ id: uuidv7(), created: "2026-03-26" },
];
rows.sort((a, b) => a.id.localeCompare(b.id));
// Thứ tự sắp xếp khớp với thời gian tạocrypto.randomUUID() vs uuid vs nanoid — So sánh nhanh
Với hầu hết dự án JavaScript: dùng crypto.randomUUID() khi bạn chỉ cần UUID v4 và runtime đủ mới. Dùng gói uuid khi bạn cần hỗ trợ v5 (tất định) hoặc v7 (có thứ tự thời gian). Dùng nanoid khi ID URL-safe ngắn thực tế hơn UUID 36 ký tự — nhưng nhớ rằng đầu ra nanoid không tuân thủ UUID và sẽ thất bại xác thực trên bất kỳ hệ thống nào mong đợi định dạng RFC 4122.
Nếu muốn tùy chọn không code, thử UUID v4 Generator để tạo định danh ngay lập tức trong trình duyệt. Để kiểm tra UUID hiện có, dán vào UUID Decoder để xem phiên bản, biến thể và bất kỳ dữ liệu timestamp nhúng nào.
Câu hỏi thường gặp
Làm thế nào để tạo UUID v4 trong JavaScript?
Gọi crypto.randomUUID() trong bất kỳ trình duyệt hiện đại nào (Chrome 92+, Firefox 95+, Safari 15.4+) hoặc Node.js 19+. Hàm này trả về một chuỗi chữ thường như "3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f". Không cần import trong trình duyệt vì crypto là một global tích hợp sẵn; trong Node.js bạn có thể dùng import { randomUUID } from "node:crypto" để rõ ràng về module. Với các runtime cũ hơn Node.js 19 vẫn có thể gọi crypto.randomUUID() trên global — nó đã có từ Node.js 14.17.0 ở chế độ thử nghiệm. Nếu bạn cần tùy chọn không cần code, công cụ UUID v4 Generator tại /en/uuid/v4 tạo ra định danh hợp lệ chỉ với một cú nhấp.
const sessionId = crypto.randomUUID(); console.log(sessionId); // "3e7f1a92-4b0c-4d8e-9f12-7a6b3c8d5e1f"
crypto.randomUUID() có an toàn về mật mã không?
Có. crypto.randomUUID() sử dụng cùng CSPRNG (bộ tạo số giả ngẫu nhiên an toàn về mật mã) như crypto.getRandomValues(). 122 bit ngẫu nhiên trong UUID v4 khiến xác suất va chạm gần như bằng không trong mọi tình huống thực tế — bạn cần tạo khoảng 2,71 triệu tỷ UUID mới đạt 50% xác suất va chạm duy nhất. Entropy đến từ nguồn ngẫu nhiên của hệ điều hành (/dev/urandom trên Linux, BCryptGenRandom trên Windows), không phải từ Math.random() vốn rõ ràng không an toàn về mật mã. Điều này có nghĩa là các giá trị UUID v4 an toàn để dùng làm session token, CSRF token và các định danh nhạy cảm về bảo mật khác. Tuyệt đối không dùng UUID generator dựa trên Math.random() trong các ngữ cảnh bảo mật.
Tôi có thể dùng UUID v4 làm khóa chính cơ sở dữ liệu không?
Bạn có thể, nhưng có một sự đánh đổi hiệu năng đáng kể. UUID v4 hoàn toàn ngẫu nhiên, nên index B-tree bị phân mảnh nặng vì mỗi hàng mới chèn vào vị trí ngẫu nhiên trong index thay vì ở cuối. Với các bảng ghi nhiều, điều này gây ra quá nhiều page split và cache miss, làm giảm hiệu năng INSERT và range-scan. Nếu database hỗ trợ (PostgreSQL, MySQL 8.0+, SQL Server), UUID v7 (có thứ tự thời gian) là lựa chọn tốt hơn cho khóa chính vì các hàng mới luôn gắn vào cuối index. UUID v4 vẫn là lựa chọn đúng cho session token, tham số OAuth state, idempotency key, correlation ID và bất kỳ trường nào mà việc ẩn thời gian tạo là mong muốn.
// UUID v4 — ngẫu nhiên, không thể sắp xếp
const correlationId = crypto.randomUUID();
// UUID v7 — có thứ tự thời gian, tốt hơn cho khóa chính DB
import { v7 as uuidv7 } from 'uuid';
const rowId = uuidv7();Sự khác biệt giữa UUID v4 và UUID v7 là gì?
UUID v4 điền 122 bit với dữ liệu ngẫu nhiên — mỗi đoạn đều là nhiễu. UUID v7 (RFC 9562, xuất bản năm 2024) mã hóa timestamp Unix millisecond 48 bit vào đoạn đầu, 12 bit độ chính xác sub-millisecond vào đoạn thứ hai, và các bit ngẫu nhiên ở phần còn lại. Cả hai đều có tổng cộng 128 bit và dùng định dạng 36 ký tự có dấu gạch ngang giống nhau, nên có thể hoán đổi ở tầng lưu trữ. UUID v7 có thể sắp xếp từ điển theo thời gian tạo, giúp index B-tree gọn gàng và truy vấn phạm vi theo khung thời gian hiệu quả. Chọn UUID v4 khi ID không được tiết lộ thời điểm tạo — ví dụ, token công khai nơi thông tin thời gian có thể bị khai thác — và UUID v7 cho khóa chính database, audit log và event stream nơi thứ tự thời gian quan trọng.
Làm thế nào để xác thực chuỗi UUID v4 trong JavaScript?
Kiểm tra với regex /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i. Chữ "4" tại vị trí 15 (đánh số từ 0) xác nhận nibble phiên bản; ký tự tại vị trí 20 — một trong 8, 9, a, hoặc b — mã hóa các bit biến thể RFC 4122. Regex này từ chối đúng UUID v1, v7 và bất kỳ chuỗi nào bị lỗi định dạng. Flag i làm cho nó không phân biệt hoa thường, nên các chữ số hex viết hoa từ các hệ thống khác đều qua xác thực mà không cần chuẩn hóa. Nếu bạn chỉ cần biết một chuỗi có phải UUID hợp lệ hay không (bất kể phiên bản), hãy dùng mẫu lỏng hơn /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.
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"); // falseLàm thế nào để tạo ID duy nhất ngắn trong JavaScript?
Bỏ dấu gạch ngang từ UUID v4 để có chuỗi hex 32 ký tự: crypto.randomUUID().replaceAll("-", ""). Để ngắn hơn nữa, dùng nanoid tạo ID URL-safe 21 ký tự (A–Z, a–z, 0–9, _ và -) theo mặc định với khả năng chống va chạm tương đương UUID đầy đủ. Sự đánh đổi rõ ràng: ID ngắn hơn có xác suất va chạm cao hơn, nhưng nanoid với 21 ký tự vẫn cung cấp 126 bit entropy, đủ cho hầu hết mọi ứng dụng thực tế. Với URL slug và dữ liệu QR code bạn có thể xuống đến 10–12 ký tự với nanoid trước khi xác suất va chạm trở thành mối lo ở tốc độ tạo thông thường. Tránh Base64-encode UUID thô rồi cắt bớt — việc cắt bớt phá vỡ tính độc lập thống kê của các bit và làm cho va chạm khó lý luận hơn.
// Chuỗi hex 32 ký tự từ UUID v4
const hexId = crypto.randomUUID().replaceAll('-', '');
// "3e7f1a924b0c4d8e9f127a6b3c8d5e1f"
// ID URL-safe 21 ký tự qua nanoid
import { nanoid } from 'nanoid';
const shortId = nanoid();
// "V1StGXR8_Z5jdHi6B-myT"Công cụ liên quan
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.