Identifiers guide ยท UUID & GUID
128 bits.
No central counter.
No collisions.
A UUID (Universally Unique Identifier) is a 128-bit value any machine can generate on its own, with no database round-trip and no coordination, and still be confident nobody else will ever generate the same one. This page explains the format, the versions, the real odds, and which one to pick for a database key. ๐
3f0f8c5a-7c22-4b1f-9f07-2f7f9a8c2041
Browser, phone, server, offline โ no need to ask a database for the next number.
Combine records from two systems without renumbering anything.
Unlike /orders/1042, a random ID doesn't reveal how many orders you have.
The standard: UUIDs are defined by RFC 9562 (published 2024), which replaced the long-standing RFC 4122 and added versions 6, 7 and 8.
02 ยท Reading one
๐ The 8-4-4-4-12 format
A UUID is 16 bytes. Its standard text form is 32 hexadecimal digits in five hyphen-separated groups of 8, 4, 4, 4 and 12 โ 36 characters in total. Two positions tell you what kind of UUID you're looking at:
| Position | In the example | Meaning |
|---|---|---|
| First digit of the 3rd group | 4b1f โ 4 | The version โ how it was generated (1โ8). |
| First digit of the 4th group | 9f07 โ 9 | The variant. 8, 9, a or b means the standard RFC layout, which is almost everything you'll see. |
| Everything else | โ | Random bits, a timestamp, or a hash, depending on the version. |
๐ชช UUID vs GUID
They're the same thing. GUID (Globally Unique Identifier) is Microsoft's name, used in Windows, COM, .NET and SQL Server. The differences are cosmetic:
- Braces. Microsoft tools often show
{3F0F8C5A-7C22-4B1F-9F07-2F7F9A8C2041}. The braces aren't part of the value. - Case. The RFC says to output lowercase and accept either case on input. Compare case-insensitively.
- Byte order. .NET's
Guid.ToByteArray()stores the first three groups little-endian, so its raw bytes differ from the RFC's order even though the string is identical. This only bites when you exchange binary UUIDs between platforms.
Special values: the nil UUID is all zeros, 00000000-0000-0000-0000-000000000000, and is commonly used as "no value". RFC 9562 also defines a max UUID of all fs.
03 ยท Which kind
๐งฌ UUID versions compared
The version decides where the 128 bits come from. In practice you'll choose between v4, v7 and, occasionally, v5.
| Version | Built from | Sortable? | Use it for |
|---|---|---|---|
| v1 | Timestamp (100 ns ticks since 1582) + clock sequence + node ID, traditionally the MAC address | Not by string | Legacy only. Leaks when and on which machine it was made. |
| v3 | MD5 hash of a namespace UUID + a name | No | Legacy deterministic IDs โ prefer v5. |
| v4 | 122 random bits | No | Default General-purpose unique IDs. |
| v5 | SHA-1 hash of a namespace UUID + a name | No | The same input always gives the same UUID โ stable IDs for URLs, emails, external keys. |
| v6 | v1's fields reordered so time sorts first | Yes | Migrating v1 systems. New designs should use v7. |
| v7 | 48-bit Unix timestamp in milliseconds + 74 random bits | Yes | Recommended Database primary keys and anything you'll sort by creation time. |
| v8 | Vendor-defined layout | Depends | Custom schemes that still want the UUID shape. |
A v5 UUID for the DNS name quickdevelopertools.com is always 6a6e3815-b43b-593b-ab56-af1731b632b9, on every machine, forever โ handy when two systems need to derive the same ID from the same natural key without talking to each other.
04 ยท The honest maths
๐ฒ Will a v4 UUID ever collide?
A v4 UUID has 128 bits, but 6 are fixed (4 for the version, 2 for the variant), leaving 122 random bits โ about 5.3 ร 1036 possible values.
The right way to think about collisions is the birthday problem: the question isn't whether a new ID matches one specific ID, it's whether any two IDs in your whole set match. That probability grows with the square of how many you've made. Even so:
โ 2.7 ร 1018
UUIDs for a 50% chance
You'd need to generate roughly 2.7 quintillion v4 UUIDs before the odds of any duplicate reach a coin flip.
โ 86 years
at a billion per second
That's how long it takes to generate that many, producing one billion UUIDs every second without stopping.
For any realistic system โ even billions of rows โ the chance of a v4 collision is so small it's dwarfed by hardware faults and ordinary bugs. You can use v4 IDs without a uniqueness check in the application, though keeping a unique constraint in the database costs little and protects you from the failure mode that does happen:
Real collisions come from bad randomness, not bad luck. A weak or badly seeded random generator โ cloned virtual machines, a fixed seed in tests, a non-cryptographic Math.random() implementation โ can produce duplicates far sooner than the maths suggests. Use your platform's built-in UUID function, which draws from a cryptographically secure source.
Unique isn't the same as secret. The RFC advises against using UUIDs as security capabilities, and v1/v7 contain readable timestamps. For API keys, reset links and session tokens, generate a dedicated random token with the Token Generator.
05 ยท Primary keys
๐๏ธ v7 for database keys & index locality
Random v4 keys have a performance cost in B-tree indexes โ the structure behind most primary keys. Each new row lands at a random spot in the index, so inserts touch pages all over it: more page splits, a larger working set that has to stay in memory, and a fragmented index over time.
v7 fixes that by putting the timestamp first. New IDs are always slightly larger than recent ones, so inserts cluster at the end of the index, much like an auto-increment integer โ while keeping the "generate anywhere" benefit.
019cebae-61c0-7a3c-9e41-5b8d0f2a6c17 โโ timestamp โโ โ โ 2026-03-14 โ โ variant 09:30:00Z โ version 7 the rest: random
๐ v7 advantages
- Index-friendly inserts
- Roughly sorts by creation time
- Still generated anywhere, no coordination
๐ Things to know
- The creation time is readable from the ID
- Ordering within the same millisecond depends on the generator
- Still 16 bytes โ twice a
bigint
SQL Server gotcha: the uniqueidentifier type doesn't sort by byte order โ it compares the last group first. A v7 GUID stored there doesn't get the locality benefit, because its timestamp is at the front. SQL Server's own answer is NEWSEQUENTIALID() as a column default; PostgreSQL's uuid type and MySQL's BINARY(16) compare bytes in order and do benefit from v7.
๐ก Store UUIDs in a native uuid / uniqueidentifier column or as 16 bytes of binary โ not as a 36-character string, which more than doubles the size of every index that includes it.
06 ยท In your code
๐ ๏ธ Generating UUIDs
crypto.randomUUID(); // v4 โ browsers (secure contexts, i.e. HTTPS) and Node.js
Guid id = Guid.NewGuid(); // v4 Guid v7 = Guid.CreateVersion7(); // v7 โ .NET 9 and later string s = id.ToString(); // "3f0f8c5a-7c22-4b1f-9f07-2f7f9a8c2041" string n = id.ToString("N"); // no hyphens bool ok = Guid.TryParse(input, out var parsed);
import uuid uuid.uuid4() # v4 uuid.uuid5(uuid.NAMESPACE_DNS, "quickdevelopertools.com") # v5 uuid.uuid7() # v7 โ Python 3.14+
-- PostgreSQL SELECT gen_random_uuid(); -- v4 (built in since PostgreSQL 13) SELECT uuidv7(); -- v7 (PostgreSQL 18+) -- SQL Server SELECT NEWID(); -- random GUID # Linux / macOS uuidgen
Need a batch right now? The GUID / UUID Generator creates one or many identifiers in the browser, in the format you need. For secrets rather than identifiers, use the Token Generator.