Regex for a UUID

/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i

A UUID is 32 hexadecimal digits in groups of 8, 4, 4, 4 and 12. Two of those digits carry meaning, and this regex checks both:

  • The first digit of the third group is the version: 4 for random UUIDs, 7 for the time-ordered ones, 1 for the old time-and-MAC kind. RFC 9562, which replaced RFC 4122 in 2024, defines versions 1 to 8, so [1-8].
  • The first digit of the fourth group is the variant. For RFC UUIDs it’s 8, 9, a or b, so [89ab].

The i flag accepts upper case, which RFC 9562 allows on input even though UUIDs are written in lower case.

What it accepts

The tester below checks one UUID per line with g, i and m; for a single value, keep only i.

f47ac10b-58cc-4372-a567-0e02b2c3d479      matches: version 4
01890a5d-ac96-774b-bcce-b302099a8057      matches: version 7
6ba7b810-9dad-11d1-80b4-00c04fd430c8      matches: version 1
F47AC10B-58CC-4372-A567-0E02B2C3D479      matches: upper case
f47ac10b58cc4372a5670e02b2c3d479          no: no hyphens
00000000-0000-0000-0000-000000000000      no: the nil UUID has no version
f47ac10b-58cc-4372-c567-0e02b2c3d479      no: variant c isn't an RFC UUID
{f47ac10b-58cc-4372-a567-0e02b2c3d479}    no: braces, as Windows writes GUIDs

Looser and stricter versions

To accept anything shaped like a UUID, including the nil UUID and Microsoft’s older variants, skip the two checks:

/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i

To accept only random UUIDs, the kind crypto.randomUUID() makes, pin the version to 4:

/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i

If your input may arrive in braces or without hyphens, normalize it first, text.replace(/[{}-]/g, ''), and check the 32 digits with /^[0-9a-f]{32}$/i.

A regex says nothing about whether a UUID was generated properly or is unique; it only checks the spelling. The UUID Generator & Decoder makes and inspects them.

Try it in the Regex Tester

Flags

4 matches

Matches

#MatchAtGroups
1f47ac10b-58cc-4372-a567-0e02b2c3d4790–36none
201890a5d-ac96-774b-bcce-b302099a805737–73none
36ba7b810-9dad-11d1-80b4-00c04fd430c874–110none
4F47AC10B-58CC-4372-A567-0E02B2C3D479111–147none

What the pattern means

  • ^The start of a line
  • [0-9a-f]{8}One of: 0–9 or a–f, exactly 8 times
    • 0-9A character from 0 to 9 (U+0030 to U+0039)
    • a-fA character from a to f (U+0061 to U+0066)
  • -The character "-"
  • [0-9a-f]{4}One of: 0–9 or a–f, exactly 4 times
    • 0-9A character from 0 to 9 (U+0030 to U+0039)
    • a-fA character from a to f (U+0061 to U+0066)
  • -The character "-"
  • [1-8]One of: 1–8
  • [0-9a-f]{3}One of: 0–9 or a–f, exactly 3 times
    • 0-9A character from 0 to 9 (U+0030 to U+0039)
    • a-fA character from a to f (U+0061 to U+0066)
  • -The character "-"
  • [89ab]One of: "8", "9", "a" or "b"
    • 8The character "8"
    • 9The character "9"
    • aThe character "a"
    • bThe character "b"
  • [0-9a-f]{3}One of: 0–9 or a–f, exactly 3 times
    • 0-9A character from 0 to 9 (U+0030 to U+0039)
    • a-fA character from a to f (U+0061 to U+0066)
  • -The character "-"
  • [0-9a-f]{12}One of: 0–9 or a–f, exactly 12 times
    • 0-9A character from 0 to 9 (U+0030 to U+0039)
    • a-fA character from a to f (U+0061 to U+0066)
  • $The end of a line
  • g global: Find every match, not just the first. exec() and test() carry on from lastIndex.
  • i ignoreCase: Letters match in either case.
  • m multiline: ^ and $ match at the start and end of each line, not just of the whole string.

Runs in your browser. Nothing you enter is sent anywhere.