/^/
HardNetworking8 min read

IPv6 Address Regex

Validates a full or zero-compressed IPv6 address, including the double-colon (::) shorthand for one run of consecutive zero groups.

#ipv6#ip-address#networking#validation#regex#advanced

Regex Pattern

^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$

Pattern Breakdown

Hover over a token to see what it does.

^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$
TokenMeaning
([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}Fully expanded form: exactly eight colon-separated groups of 1-4 hex digits
([0-9a-fA-F]{1,4}:){1,7}:One to seven groups followed by a trailing double colon, e.g. 2001:db8::
([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}Compressed form with the zero run before the final group
[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})A single leading group followed by a compressed run of up to six more groups
:((:[0-9a-fA-F]{1,4}){1,7}|:)Address starting with :: followed by up to seven groups, or the all-zero address :: itself
[0-9a-fA-F]{1,4}One hextet: one to four hexadecimal digits representing 16 bits
$Anchors the match to the end of the string

Detailed Explanation

What it does

This pattern validates IPv6 addresses written in their standard colon-hexadecimal notation, supporting both the fully expanded eight-group form and the zero-compression shorthand (::) that collapses one run of consecutive all-zero groups. It correctly matches addresses like 2001:db8::1 as well as fe80::1ff:fe23:4567:890a.

Why it works

IPv6 addresses have eight 16-bit groups, but the :: shorthand can replace exactly one run of consecutive zero groups anywhere in the address, which means the number of explicit groups before and after :: can vary. The pattern handles this by enumerating every valid combination as a large alternation: the fully expanded 8-group form with no compression, and then one branch for each possible position of the :: (from compressing after the first group down to a single-group address), each branch counting how many groups appear before and after the double colon so the total never implicitly exceeds eight.

Common use cases

  • Validating IPv6 input fields in network configuration UIs
  • Filtering log files or configuration for lines containing IPv6 literals
  • Distinguishing IPv6 addresses from IPv4 or hostnames in mixed data
  • Pre-validating addresses before passing them to socket or DNS resolution APIs

Edge cases

  • The all-zero address :: is valid shorthand for 0:0:0:0:0:0:0:0 and matches via the final alternation branch
  • Addresses with only one :: compression are valid; a second :: like 2001:db8::85a3::8a2e is invalid and correctly rejected
  • Leading zeros within a group are optional, so 2001:0db8::1 and 2001:db8::1 are both valid and match
  • Groups longer than four hex digits, like 12345::, are correctly rejected
  • This pattern does not natively support the embedded-IPv4 tail form (e.g. ::ffff:192.168.1.1) without an additional branch

Limitations

  • Does not validate the embedded IPv4-mapped IPv6 notation (::ffff:a.b.c.d) out of the box
  • Does not handle zone/scope IDs used for link-local addresses, such as fe80::1%eth0
  • Extremely long due to enumerating every compression position, which makes it harder to read and maintain than the IPv4 pattern
  • Cannot verify the address is actually assigned, routable, or reachable

Interactive Tester

Edit the pattern or text below — matching runs live in your browser.

2001:0db8:85a3:0000:0000:8a2e:0370:7334 2001:db8:85a3::8a2e:370:7334 ::1

Test Cases

Editable — add your own inputs to see if they pass.

InputExpectedResult
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass

Language Variants

Production-ready examples in 12 languages.

const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
console.log(ipv6Regex.test('2001:db8::1')); // true

Common Mistakes

Assuming a simple pattern like [0-9a-fA-F:]+ is enough to validate IPv6, which accepts malformed strings like too many colons

Fix: Use the full alternation that enumerates valid group counts and :: compression positions, or better, use your language's built-in IP parser

Not accounting for the fact that :: can only appear once in a valid address

Fix: The alternation branches each assume a single :: position; reject any string containing two separate :: occurrences

Forgetting that IPv6 addresses can embed an IPv4 tail (::ffff:192.168.1.1) which this base pattern does not match

Fix: Add a dedicated alternation branch for the IPv4-mapped form if your application needs to accept it

Hand-rolling IPv6 validation in production code instead of using a standard library parser

Fix: Prefer built-in APIs like Python's ipaddress module, Go's net.ParseIP, or C#'s IPAddress.TryParse for authoritative validation, and reserve regex for quick client-side checks

Performance Notes

  • This pattern is long because it enumerates every valid position of the :: compression as a separate alternation branch
  • Alternation with overlapping prefixes (many branches starting with ([0-9a-fA-F]{1,4}:)) can cause the engine to backtrack across branches on non-matching input, though bounded by the fixed 8-group structure so it stays polynomial, not exponential
  • For hot-path validation, prefer a native IP-parsing library over regex since it is both faster and more correct
  • Anchoring with ^ and $ is essential given how many branches could otherwise partially match a longer invalid string

Browser Compatibility

EngineSupportedNotes
ChromeYes
FirefoxYes
SafariYes
EdgeYes
Node.jsYes