UUID Generator
Generate UUID v4 identifiers in bulk.
What is a UUID?
A UUID (Universally Unique Identifier) is a 128-bit value standardized in RFC 9562, the May 2024 update that replaces the long-running RFC 4122. The canonical printed form is 32 lowercase hexadecimal digits arranged in five groups separated by hyphens: 8-4-4-4-12. Two specific positions inside that string carry structural meaning rather than payload bits. The 13th hex digit (the first character of the third group) is the version nibble, fixed to 4 for a v4 UUID, 1 for v1, 5 for v5, and 7 for v7. The 17th hex digit (the first character of the fourth group) holds the variant bits, set to 8, 9, a, or b for any UUID that follows the RFC 9562 variant.
Worked example: 550e8400-e29b-41d4-a716-446655440000. Reading left to right, the third group 41d4 opens with the version nibble 4, telling us this is a v4 UUID generated from random bits. The fourth group a716 opens with a, a valid RFC variant marker. The remaining 122 bits (everything outside those two reserved nibbles) carry the actual entropy. The 128-bit width is identical across every version, so the storage and on-the-wire footprint never changes regardless of which generation algorithm produced the value.
Choosing a UUID version
RFC 9562 defines six versions, but four of them dominate real-world code. The choice between them is not stylistic. Each version trades a different property against random-only entropy, and picking the wrong one shows up months later as either a security audit finding or a database performance regression.
- v1 embeds a 60-bit timestamp and the originating machine's 48-bit MAC address. The result is sortable by creation time, which is useful, but it leaks the MAC of the host that minted it, which is not. Most modern stacks treat v1 as deprecated and reach for v7 when time-ordering matters.
- v4 packs 122 random bits with no embedded metadata. Collision odds are roughly 1 in 5.3x10^36, which is the same order of magnitude as the number of atoms in 100 kilograms of water. v4 is the correct default for API request IDs, message envelopes, and anywhere ordering is irrelevant.
- v5 takes a SHA-1 hash of a namespace UUID concatenated with a name string, then masks in the version and variant bits. The output is fully deterministic: the same namespace and name always yield the same UUID. We reach for v5 when minting a stable internal ID derived from an external system's primary key (a Stripe customer ID, a GitHub repo full name) so that re-ingestion is idempotent.
- v7 prepends a 48-bit Unix-millisecond timestamp followed by 74 random bits. Successive inserts therefore land on the rightmost page of a b-tree primary-key index instead of scattering across pages, and the index pages stay hot in the OS cache because new rows always hit the same locality. On a typical Postgres bulk-insert benchmark, v7 primary keys run roughly 2-4x faster than v4 primary keys at scale, with dramatically less write amplification.
Worked example: insert one million rows into a Postgres table with a UUID primary key. With v4, every insert hits a random b-tree leaf page, the buffer pool churns, and bulk-load throughput collapses well below sequential-key baselines. Swap the same table to v7 and the throughput climbs back near serial-integer territory, because the index is effectively append-only against its rightmost edge. Secondary-index performance is identical across versions, so the win is concentrated entirely on the primary-key b-tree.
Common pitfalls
UUIDs look interchangeable on the page, and that visual uniformity is exactly what makes the misuses below so common. Each of these has shown up in production audits we have walked through, and each is preventable by picking the right primitive at the right layer instead of letting a generic v4 string carry weight it was not designed for.
- Using v4 UUIDs as session tokens or password reset tokens. The 122 bits of entropy are technically sufficient, but UUIDs are routinely logged on purpose (request IDs, trace IDs, error reports) and the version nibble at hex position 13 reveals structure that a pure-random token would not. We mint auth-adjacent identifiers from a dedicated CSPRNG: 32 bytes from
crypto.getRandomValues, Base64URL-encoded, handled like a password and never logged. - Storing UUIDs as
CHAR(36)orVARCHAR(36)in MySQL. The hyphenated string form occupies 36 bytes; the raw 128-bit value occupies 16. Switching the column toBINARY(16)is roughly 2.25x more compact on disk and 2-3x faster on primary-key lookup because more index entries fit in each b-tree page. The conversion is a one-lineUNHEX(REPLACE(uuid, '-', ''))on write and a matchingHEXon read. - Picking v1 because somebody asked for "sortable IDs." v1 leaks the host MAC address into every emitted value, which is a privacy and fingerprinting problem the moment those IDs cross a trust boundary. RFC 9562 codifies v7 as the modern replacement, and we have not minted a new v1 in production code since the 9562 draft stabilized.
- Generating UUIDs on the client without
crypto.randomUUID(). AMath.random-based fallback is biased, predictable, and not collision-safe at scale.crypto.randomUUID()draws from the platform CSPRNG and ships natively in Node.js 14.17+, Chromium 92+, Firefox 95+, and Safari 15.4+. There is no remaining browser we support that justifies a polyfill.
When to use this tool
We built the generator for three concrete workflows. The first is a QA engineer minting bulk seed data for a test fixture: a hundred v4 IDs at once, copied straight into a SQL script or a JSON test bundle, with no shell loop and no language-specific snippet to babysit. The second is a backend dev producing a v5 UUID derived from an external system's primary key (a Stripe customer ID, a Salesforce account ID, an Auth0 user_id) so the resulting internal record can be re-derived idempotently the next time the same record arrives through the ingestion pipeline. The third is an architect demonstrating v7 time-ordering during a design review: generating a handful of v7s in sequence shows the timestamp prefix advancing visibly across the first six hex characters, which sells the b-tree-friendliness argument faster than a benchmark slide does.
Frequently asked
- Which UUID version should I use?
- Editorial. v4 for general-purpose IDs in API responses, message envelopes, and anywhere a sortable property is irrelevant. v7 when the UUID is a database primary key and inserts hit a b-tree, because the time-ordered prefix prevents index fragmentation. v5 when we need the same input to deterministically yield the same UUID (idempotent ingestion, stable IDs derived from external keys). Avoid v1: it leaks the originating MAC address and is effectively replaced by v7 under RFC 9562.
- Are UUIDs really unique?
- Effectively yes. v4 has 122 random bits, giving roughly 5.3x10^36 possible values. The birthday-paradox math says we would need to generate about 2.71 quintillion UUIDs (2.71x10^18) to hit a 50% chance of a single collision. At one billion UUIDs per second, that takes roughly 86 years of continuous generation. No production workload we have shipped against has come within 12 orders of magnitude of that threshold.
- Can I use a UUID as a session token?
- Discouraged. The 122 bits of entropy in a v4 are technically sufficient, but two practical issues bite. UUIDs are routinely logged inadvertently (request IDs, trace IDs, error reports), and the v4 version nibble at hex position 13 reveals structure that pure-random tokens do not. We use a dedicated CSPRNG token for any auth-adjacent identifier: 32 bytes from `crypto.getRandomValues`, Base64URL-encoded, treated like a password in handling.
- Why is v7 better for database keys than v4?
- v7 prepends a 48-bit Unix-millisecond timestamp, so successive inserts always hit the rightmost page of a b-tree index. v4 IDs hit random pages, fragment the index, and force the buffer pool to swap pages that should stay hot. On Postgres bulk-insert benchmarks, v7 PKs run 2-4x faster than v4 PKs at scale and produce dramatically less write amplification. Secondary-index performance is identical between the two, so the win is purely on the PK b-tree.
- How do I generate UUIDs in JavaScript, Python, or SQL?
- JavaScript: `crypto.randomUUID()` returns a v4 string and ships natively in Node.js since 14.17 and in every evergreen browser since 2021. Python: `uuid.uuid4()` from the standard library. Postgres: `gen_random_uuid()` produces a v4, built in since version 13. For v7 we reach for the `uuid` npm package (`v7()` since 9.0), the `uuid6` Python package, or the `uuid_generate_v7()` function in `pg_uuidv7` extension on Postgres.
- Is `crypto.randomUUID()` safe for production?
- Yes. It draws bytes from the platform CSPRNG (`/dev/urandom`, `BCryptGenRandom`, or the equivalent), formats them per RFC 9562, and always returns a v4. Available since Node.js 14.17, Chromium 92, Firefox 95, and Safari 15.4. We use it directly in production without a polyfill or wrapper. The only caveat: the returned string is v4 only, so when v7 is needed, reach for the `uuid` npm package instead.