UUID Regex
UUID validation by layout and by meaning — a case-insensitive 8-4-4-4-12 gate plus a version-and-variant strict form, CI-verified.
Pattern variants
Pragmatic
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
What it matches
The 8-4-4-4-12 hex layout in either case (flag i).
What it deliberately doesn't
Version or variant correctness, brace-wrapped or hyphen-less forms.
Strict
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
What it matches
RFC 4122 UUIDs only: version nibble 1-5 and variant nibble 8, 9, a or b.
What it deliberately doesn't
The nil UUID and post-4122 versions like UUIDv7 — widen [1-5] to [1-8] if you accept them.
Verified vectors
| Input | Pragmatic | Strict | Note |
|---|---|---|---|
"123e4567-e89b-12d3-a456-426614174000" | ✓ matches | ✓ matches | |
"123E4567-E89B-12D3-A456-426614174000" | ✓ matches | ✓ matches | uppercase — flag i accepts either case |
"00000000-0000-0000-0000-000000000000" | ✓ matches | ✗ no match | the nil UUID — no version, fails strict by design |
"123e4567-e89b-72d3-a456-426614174000" | ✓ matches | ✗ no match | version 7 (RFC 9562) — widen [1-5] to [1-8] to accept it |
"123e4567-e89b-12d3-c456-426614174000" | ✓ matches | ✗ no match | variant nibble outside 8, 9, a, b |
"123e4567e89b12d3a456426614174000" | ✗ no match | ✗ no match | no hyphens |
"{123e4567-e89b-12d3-a456-426614174000}" | ✗ no match | ✗ no match | brace-wrapped form |
"123e4567-e89b-12d3-a456-42661417400" | ✗ no match | ✗ no match | one hex digit short |
"g23e4567-e89b-12d3-a456-426614174000" | ✗ no match | ✗ no match | g is not a hex digit |
"123e4567-e89b-12d3-a456-426614174000 " | ✗ no match | ✗ no match | trailing space — anchors reject it |
Usage by language
JavaScript
Machine-verified/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
Python
Machine-verifiedre.compile(r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", re.IGNORECASE)
re.compile(r"^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", re.IGNORECASE)
Java
Syntax-reviewed — not machine-verifiedPattern.compile("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", Pattern.CASE_INSENSITIVE)
Pattern.compile("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", Pattern.CASE_INSENSITIVE)
Go
Syntax-reviewed — not machine-verifiedregexp.MustCompile(`(?i)^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
regexp.MustCompile(`(?i)^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`)
C#
Syntax-reviewed — not machine-verifiednew Regex(@"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", RegexOptions.IgnoreCase)
new Regex(@"^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", RegexOptions.IgnoreCase)
PHP
Syntax-reviewed — not machine-verified'/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i'
'/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i'
Caveats
- Canonical UUIDs are lowercase (RFC 4122), but parsers accept either case — hence flag i.
- Strict pins version 1-5 and the RFC 4122 variant; the nil UUID and UUIDv7 (RFC 9562) fail it by design.
Related patterns
Do it offline:$ grep -E -i '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' ids.txt
How to use it
- Validate path parameters and foreign keys with the pragmatic layout check — malformed ids fail before any database round trip.
- Turn on strict where provenance matters — it refuses the nil UUID and ids no RFC 4122 generator would emit.
- Working with UUIDv7? Widen the version class to [1-8] in the tester, as the deliberately-not block advises.
Every UUID is thirty-two hex digits wearing four hyphens in an 8-4-4-4-12 grid. The pragmatic pattern checks that layout under the i flag — RFC 4122 canonicalizes to lowercase, parsers accept either case. Strict also reads the two meaningful nibbles: version 1 through 5 and variant 8, 9, a or b. Ten CI-verified vectors follow.
Examples
^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$pattern /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
123e4567-e89b-12d3-a456-426614174000 ✓ matches
123E4567-E89B-12D3-A456-426614174000 ✓ matches
123e4567e89b12d3a456426614174000 ✗ no match
g23e4567-e89b-12d3-a456-426614174000 ✗ no matchCase folding comes from the i flag, not the classes; strip hyphens or slip in a non-hex letter and the grid refuses.
^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$pragmatic /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
strict /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
input 123e4567-e89b-72d3-a456-426614174000
pragmatic ✓ matches
strict ✗ no match
input 00000000-0000-0000-0000-000000000000
pragmatic ✓ matches
strict ✗ no matchBoth ids are perfectly shaped — the point: a version-7 id and the all-zero nil UUID pass the layout gate and fail the nibble check. Pragmatic reads shape; strict reads meaning.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
RFC 9562 moved the version ceiling
The strict class [1-5] encodes RFC 4122's world; RFC 9562 since defined versions 6 through 8, and v7's millisecond-ordered ids are spreading. Widening to [1-8] is a one-character edit — make it consciously, never by copy-paste accident.
Common errors
duplicate regex flag "i"- Combining this page's i with a snippet already carrying one doubles the flag, and flags must be unique — the refusal is the engine's own wording. Keep one i; case folding does not stack.
FAQ
Should stored UUIDs be lowercase or uppercase?
Emit lowercase — RFC 4122 calls it canonical — and compare case-insensitively, as the i flag encodes. Normalizing on write keeps string equality and uniqueness honest.
Why does the nil UUID fail the strict variant?
The all-zero id carries version 0 and variant 0 — no RFC 4122 algorithm emits it; it is a sentinel. If your schema uses nil as empty, test for it before the nibble check.
Can the regex tell me which version generated an id?
It gates versions without reporting them — strict accepts 1 through 5 wholesale. To read one, take the first digit after the second hyphen; a string slice does it, no pattern needed.