UUID v4 Explained: Uniqueness, Formats and Use Cases
The UUID v4 format, collision odds calculated, generation and validation tested in Node.js, Python and WordPress, and an SQLite test of random v4 versus time-ordered v7 keys.
On this page
A UUID v4 is a 128-bit identifier made almost entirely of random bits. It is written as 32 hexadecimal characters in five groups, such as 9c5c2c40-9d47-442e-a2ef-0363b1eb6155. Six bits are fixed: the "4" at the start of the third group marks the version, and the first character of the fourth group is always 8, 9, a or b. The other 122 bits are random, so two systems can create IDs independently with practically no chance of a clash. Use v4 when you need IDs that are unique, unguessable in order and created without a central counter. If the ID is a database primary key and insert speed matters, consider the newer time-ordered UUID v7.
This post explains the format, the real collision odds and how to generate and validate v4 UUIDs in JavaScript, Python, PHP and WordPress. It also covers when v7 is the better choice. We generated UUIDs in each environment and checked their version and variant bits. We also ran a small SQLite test comparing random v4 keys with time-ordered v7 keys.
The format
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
^ ^
version variant (y is 8, 9, a or b)
Table: Anatomy of a UUID v4
| Part | Length | Content |
|---|---|---|
| Group 1 | 8 hex characters | Random |
| Group 2 | 4 | Random |
| Group 3 | 4 | "4" (version), then random |
| Group 4 | 4 | Variant (8, 9, a or b), then random |
| Group 5 | 12 | Random |
UUIDs are defined in RFC 9562 (published May 2024), which replaced the older RFC 4122. It describes v4 as meant for generating UUIDs from truly random or pseudorandom numbers, with 122 random bits. The text form is 36 characters including hyphens; the underlying value is 16 bytes. Letters are case-insensitive, and lowercase is the usual output.
<h2
How unique is "unique"?
With 122 random bits there are about 5.3 × 10³⁶ possible values. The chance of any collision among n random UUIDs is roughly n² ÷ (2 × 2¹²²). We calculated:
Table: Approximate probability of at least one collision (calculated)
| UUIDs generated | Collision probability |
|---|---|
| 1 million | about 9.4 × 10⁻²⁶ |
| 1 billion | about 9.4 × 10⁻²⁰ |
| 1 trillion | about 9.4 × 10⁻¹⁴ |
| 1 quadrillion | about 9.4 × 10⁻⁸ |
| For a 50% chance | about 2.7 × 10¹⁸ UUIDs |
In practice, bugs cause duplicates long before chance does: a weak random number generator, copying a UUID instead of generating a new one, or a cloned virtual machine reusing random state. Always use a cryptographically secure generator, and still put a unique constraint on database columns.
Before you use UUIDs
- Decide what the ID is for: a public reference, a database key, a file name, an idempotency key for an API.
- Decide how to store it. A native UUID or 16-byte binary column is smaller and faster than a 36-character string.
- Use a trusted generator from your language's standard library, not a hand-rolled function based on
Math.random(). - Remember UUIDs are not secrets. They are hard to guess but not designed as access tokens; use proper authentication for anything sensitive.

Generating UUID v4
// JavaScript (browsers and Node.js)
crypto.randomUUID();
// '10b24151-1d9d-4f6a-ab6a-61c9e1e12d0d'
# Python
import uuid
str(uuid.uuid4())
// PHP in WordPress
$id = wp_generate_uuid4();
We generated one with each and confirmed the version and variant: Node.js crypto.randomUUID(), Python's uuid.uuid4() (which reported version 4) and WordPress 7.1.3's wp_generate_uuid4(), which its own wp_is_uuid( $id, 4 ) accepted. For quick one-off IDs, or a batch of up to 1,000, the UUID generator uses the browser's crypto.randomUUID() and can output uppercase, without hyphens or wrapped in braces.
Validating a UUID v4
This regular expression accepts lowercase v4 UUIDs with hyphens; add the i flag to accept uppercase:
^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
All three UUIDs from our test matched it. Test it against your own samples in the regex tester. In code, prefer the platform's parser where one exists, such as Python's uuid.UUID(value).version or WordPress's wp_is_uuid(), which also handles uppercase.
Use cases
Table: Where UUID v4 fits
| Use | Why UUID v4 helps |
|---|---|
| IDs created on many servers or offline devices | No central counter is needed; IDs will not clash when data is merged |
| Public references in URLs or APIs | Does not reveal how many records exist or allow guessing the next ID |
| Idempotency keys for payment or API requests | Lets a server recognise a retried request |
| File names for uploads | Avoids name collisions and hides the original file name |
| Correlation IDs in logs | Links log entries from one request across services |
Where they fit less well: short human-readable codes (use a shorter scheme), and high-volume database primary keys where insert performance matters (consider v7).
The other UUID versions in brief
Table: UUID versions defined in RFC 9562
| Version | Based on | Typical use today |
|---|---|---|
| 1 | Timestamp and a node identifier (often a MAC address) | Legacy systems; can reveal the machine and time |
| 3 and 5 | A hash of a namespace and a name (MD5 for v3, SHA-1 for v5) | The same input always gives the same UUID |
| 4 | Random bits | General-purpose unique IDs |
| 6 | Reordered v1 timestamp | Upgrading v1 systems to sortable IDs |
| 7 | Unix timestamp in milliseconds plus random bits | Sortable IDs, especially database keys |
| 8 | Custom, vendor-defined layout | Special cases |
The RFC says implementations should use v7 instead of v1 and v6 where possible. For most new work, the practical choice is between v4 and v7.
UUID v4 versus v7
RFC 9562 also defines UUID v7, which starts with a millisecond Unix timestamp followed by random bits. That makes v7 values sort roughly by creation time. The RFC notes that versions which are not time-ordered, such as v4, have "poor database-index locality". New random keys land all over the index rather than at the end.
We ran a small illustrative test: inserting 300,000 rows into an SQLite table keyed by UUID text, in batches of 1,000.
Table: SQLite insert test, 300,000 rows (two runs each)
| Key type | Insert time | Database size |
|---|---|---|
| UUID v4 (random) | 0.84 s, 0.82 s | 14.1 MB |
| UUID v7 (time-ordered) | 0.36 s, 0.40 s | 13.9 – 14.0 MB |
Ordered keys inserted roughly twice as fast in this test. Results vary by database, storage and table size, but the direction matches the RFC's note. Choose v7 for database keys when ordering helps and revealing the approximate creation time is acceptable. Choose v4 when IDs must reveal nothing, including when they were created.
Worked example: an order reference
An illustrative shop shows customers order numbers like /orders/1042/. Customers can guess that the shop takes about 40 orders a week, and anyone who tries /orders/1043/ reaches a login check. Switching the public reference to a UUID v4 (/orders/9c5c2c40-9d47-442e-a2ef-0363b1eb6155/) hides the order count and makes guessing pointless. The shop keeps its sequential number internally for staff, and still protects the order page with authentication, because an unguessable ID is not a password.
Storage and size tips
- Binary storage: 16 bytes instead of 36 characters. Many databases have a native UUID type.
- Shorter text form: encode the 16 bytes as URL-safe Base64 (22 characters) if you need compact URLs. The Base64 encoder has a URL-safe option.
- Consistent case: store lowercase to avoid duplicates that differ only in case.
- In JSON: send UUIDs as strings. A JSON validator catches unquoted values that would break parsing.
Verify your implementation
- Generate a sample and check the third group starts with 4 and the fourth with 8, 9, a or b.
- Confirm the generator uses a cryptographically secure source.
- Add a unique constraint to database columns that hold UUIDs.
- Normalise case before comparing or storing.
- Test parsing of uppercase, braces and no-hyphen forms if you accept input from other systems.
Common mistakes
- Building UUIDs from
Math.random()or timestamps instead of a secure generator. - Treating a UUID as a secret access token.
- Storing UUIDs as 36-character strings in very large tables without considering binary storage.
- Comparing UUIDs case-sensitively.
- Using random v4 keys for huge, insert-heavy tables without considering v7.
- Validating with a pattern that rejects valid uppercase input.
Troubleshooting
Table: UUID problems and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Duplicate UUIDs | Weak generator, copied values or reused random state | Use the platform's secure generator; add a unique constraint |
| Validation rejects valid IDs | Case-sensitive pattern, or braces and missing hyphens | Normalise input, or use a parser |
| Slow inserts on a large table | Random keys scattering index writes | Consider UUID v7 or a separate sequential key |
crypto.randomUUID is undefined |
Very old browser or a non-secure (HTTP) page | Serve over HTTPS; fall back to crypto.getRandomValues() |
| Version digit is not 4 | The value is a different UUID version | Check which version your system expects |
Frequently asked questions
What is a UUID v4?
A 128-bit identifier with 122 random bits, a version digit of 4 and a variant digit of 8, 9, a or b, written as 36 characters with hyphens.
Can two UUID v4s be the same?
In theory yes, but the odds are tiny: about 9.4 × 10⁻²⁰ across a billion UUIDs. Duplicates in practice come from bugs, not chance.
Is a UUID v4 secure?
It is hard to guess when generated securely, but it is not designed as a secret. Do not use it as the only protection for private data.
What is the difference between UUID and GUID?
GUID is Microsoft's name for the same kind of identifier. The formats are compatible, though GUIDs are often shown in uppercase or with braces.
How long is a UUID?
128 bits, or 16 bytes. As text it is 36 characters with hyphens, or 32 without.
Should I use UUID v4 or v7 for database keys?
v7 is time-ordered, which helps index performance; in our SQLite test it inserted about twice as fast. Use v4 when the ID must not reveal its creation time.
Which RFC defines UUIDs?
RFC 9562, published in May 2024, which replaced RFC 4122.
How do I generate a UUID in WordPress?
Call wp_generate_uuid4(). You can check a value with wp_is_uuid( $value, 4 ).
Are UUIDs case-sensitive?
No. The hexadecimal letters can be upper or lower case, but store them consistently, usually lowercase.
Can I shorten a UUID?
Yes, by encoding the 16 bytes in Base64 (22 characters URL-safe). It is the same value, just a shorter text form.
Next step
Generate a few IDs with the UUID generator, test your validation against them in the regex tester, and decide whether your database keys would benefit from v7. More developer topics are in our developer guides.
Related free tools for this topic
UUID Generator (v4)
Generate one or up to 1,000 random v4 UUIDs at once, with uppercase, no-hyphen and brace options.
Merge PDF Files Online (Free, No Uploads)
Combine multiple PDF documents into a single file directly in your browser. Reorder pages, keep your files private,…
Images to PDF Converter (JPG, PNG, WebP to PDF)
Turn screenshots, mockups, and loose images into one organized, properly sized PDF. Choose A4, US Letter, or fit…
Organise PDF: Reorder, Rotate & Extract Pages (Free)
Rearrange, rotate, delete or extract specific pages from any PDF document in your browser. Use visual page controls…
PDF to Images (JPG & PNG Converter)
Convert PDF pages into crisp PNG or JPEG images in your browser. Choose resolution scale (1× to 3×)…
SVG Optimiser for Web & Elementor (Clean viewBox & currentColor)
Shrink SVG icons, preserve the viewBox, remove fixed dimensions, and make vectors adapt to Elementor colours using currentColor.…
Related resources
SaaS hero with dashboard preview
Two-column hero: headline, supporting text, two buttons and a trust line beside a visual panel. Stacks to one…
Centred SaaS hero with product window
Centred hero with a large headline, supporting text and two buttons, with optional highlights and a product window…
Dark studio hero with service highlights
Centred hero with a large headline, supporting text and two buttons, with optional highlights and a product window…
Related articles
Unix Timestamps: Seconds, Milliseconds and Time Zones
What a Unix timestamp is, why seconds and milliseconds get mixed up, how to convert correctly in JavaScript, PHP, Python and WordPress,…
SHA-256 vs MD5: Hashing for Checksums, Not Passwords
MD5 is broken for collision resistance; SHA-256 is not, and on our test machine it was faster. Where each fits, how to…
Minifying CSS: What It Saves and When Your Build Should Do It
We minified WordPress core stylesheets with five tools and compressed the results: what minification saves on top of gzip and Brotli, and…
Related guides
How Long Should a Meta Title Be? Pixels vs Characters Explained
"Keep it under 60 characters" is only half right. Google cuts titles by pixel width, not character count. Learn how to write…
The Default WordPress .htaccess File (and Safe Additions)
The exact .htaccess rules WordPress needs for pretty permalinks, what each line does, tested additions for HTTPS and file protection, and a…
Fluid Typography in Elementor with clamp()
Setting a heading to 56 px on desktop, 44 px on tablet and 32 px on mobile works, but text jumps between…
Comments