IPv6 CIDR Notation Regex
Validates an IPv6 address written in CIDR (Classless Inter-Domain Routing) notation, such as 2001:db8::/32 or ::1/128, including the zero-compressed :: shorthand and a prefix length from 0 to 128.
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}|:))\/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9])$Pattern Breakdown
Hover over a token to see what it does.
| Token | Meaning |
|---|---|
| (?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4} | Fully expanded form: eight groups of 1-to-4 hex digits separated by colons, with no :: compression |
| (?:[0-9A-Fa-f]{1,4}:){1,7}: | Compressed form where the address ends in ::, meaning the remaining groups are all zero |
| (?:[0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4} | One of several branches handling :: compressed somewhere in the middle of the address, with a different split point per branch |
| :(?:(?::[0-9A-Fa-f]{1,4}){1,7}|:) | Handles addresses that start with :: (leading zero groups), including the all-zeros address :: itself |
| \/ | Literal slash separating the address from the CIDR prefix length |
| 12[0-8]|1[01][0-9]|[1-9]?[0-9] | Prefix length from 0 to 128: 120-128, 100-119, or 0-99, split into three numeric ranges |
| $ | Anchors the match to the end of the string |
Detailed Explanation
What it does
This pattern validates a complete IPv6 address in CIDR notation: the address portion (in any of its valid textual forms, including zero-compression with ::) followed by a slash and a subnet prefix length between 0 and 128.
Why it works
IPv6 addresses have eight 16-bit groups, but the standard allows at most one run of consecutive all-zero groups to be collapsed into ::. Because that collapse can happen at the start, middle, end, or not at all, the pattern is built as an alternation of branches, each one fixing how many groups appear before and after the ::, or requiring all eight groups with no compression. The prefix length is validated with three numeric alternatives instead of a single range quantifier because regex has no built-in way to express 'a number between 0 and 128' directly.
Common use cases
- Validating subnet definitions in firewall rules, routing tables, or network ACLs
- Parsing IPv6 CIDR blocks from infrastructure-as-code configuration files
- Checking user input in a network management dashboard where operators enter subnets manually
- Filtering log entries or CSV exports to find lines describing IPv6 subnets
Edge cases
- The all-zeros address with maximum prefix, ::1/128, is matched
- The default route ::/0 is matched, representing the entire IPv6 address space
- A fully expanded address with no compression, like 2001:0db8:85a3:0000:0000:8a2e:0370:7334/64, is matched
- A prefix length of 129 or higher is rejected since valid IPv6 prefixes only go up to 128
- An address with more than one :: compression, like 2001:db8::1::2/64, is rejected because only one branch of the alternation can match at a time and none permit two double-colons
- A missing prefix length entirely, like 2001:db8::1 with no slash and number, is rejected since the /prefix suffix is mandatory in this pattern
Limitations
- Does not support embedded IPv4-mapped IPv6 addresses like ::ffff:192.168.1.1
- Does not verify that the host bits beyond the prefix length are actually zero, so 2001:db8::1/32 passes even though a strict network address would require the trailing bits to be clear
- Does not support zone IDs (scope identifiers) like fe80::1%eth0
- The alternation is long and can be harder to maintain than a small parsing function, though it remains linear-time and safe from catastrophic backtracking
Interactive Tester
Edit the pattern or text below — matching runs live in your browser.
Test Cases
Editable — add your own inputs to see if they pass.
| Input | Expected | Result | |
|---|---|---|---|
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass |
Language Variants
Production-ready examples in 12 languages.
const ipv6CidrRegex = /^(?:(?:[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}|:))\/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
console.log(ipv6CidrRegex.test('2001:db8::/32')); // trueCommon Mistakes
Writing a single simplified branch like ([0-9A-Fa-f]{1,4}:){1,7}[0-9A-Fa-f]{0,4} and expecting it to fully validate :: compression rules
Fix: Use a full alternation with one branch per valid position of the :: compression, since a single simplified pattern cannot correctly enforce that only one compression run is allowed
Forgetting the prefix length range check and using \d{1,3} for the CIDR suffix, which lets invalid values like /200 pass
Fix: Split the prefix length into explicit numeric ranges (0-99, 100-119, 120-128) since regex has no native numeric comparison
Assuming this pattern also validates that host bits past the prefix length are zero
Fix: Perform a separate bitwise check in application code after parsing the address if strict network-address validation is required
Performance Notes
- The alternation has eight mutually exclusive branches, and most engines try each in order, so worst-case matching is still linear in the length of a single address string, not exponential
- Anchoring with ^ and $ prevents the engine from retrying the entire alternation at multiple starting offsets
- Because each branch uses bounded quantifiers ({1,4}, {1,7}, etc.) rather than unbounded nested repetition, this pattern does not exhibit catastrophic backtracking even on malformed long input
Browser Compatibility
| Engine | Supported | Notes |
|---|---|---|
| Chrome | Yes | — |
| Firefox | Yes | — |
| Safari | Yes | — |
| Edge | Yes | — |
| Node.js | Yes | Long alternations like this compile without issue but are easier to maintain when built from smaller named sub-patterns |