New blogMaking an AI Agent You Can Trust With Money

★ Web · regex

Regex for IPv6 Address

Covers the eight-group form and every legal placement of the :: shorthand. It does not cover zone IDs (%eth0) or IPv4-embedded forms like ::ffff:192.0.2.1.

  • Runs in your browser
  • No signup

Try the ipv6 address pattern

Read it in plain English (best-effort)

  • ^start of a line
  • (?:start a group (not captured)
  • (?:start a group (not captured)
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • :the character ':'
  • )end of group
  • {7}exactly 7 of the previous
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • |or
  • (?:start a group (not captured)
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • :the character ':'
  • )end of group
  • {1,7}between 1 and 7 of the previous
  • :the character ':'
  • |or
  • (?:start a group (not captured)
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • :the character ':'
  • )end of group
  • {1,6}between 1 and 6 of the previous
  • :the character ':'
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • |or
  • (?:start a group (not captured)
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • :the character ':'
  • )end of group
  • {1,5}between 1 and 5 of the previous
  • (?:start a group (not captured)
  • :the character ':'
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • )end of group
  • {1,2}between 1 and 2 of the previous
  • |or
  • (?:start a group (not captured)
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • :the character ':'
  • )end of group
  • {1,4}between 1 and 4 of the previous
  • (?:start a group (not captured)
  • :the character ':'
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • )end of group
  • {1,3}between 1 and 3 of the previous
  • |or
  • (?:start a group (not captured)
  • [0-9A-Fa-f]one character from: 0–9, A–F, a–f
  • {1,4}between 1 and 4 of the previous
  • :the character ':'
  • )end of group
  • +44 more

One sample per line works well with the m flag on anchored patterns.

Waiting for a pattern
01

The pattern, piece by piece

/^(?:(?:[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 explanation
PartWhat it does
[0-9A-Fa-f]{1,4}one group of 1–4 hex digits
(?:group:){7}groupthe full eight-group form
…:(?::group){n}each alternative places the :: gap in a different position
:(?:(?::group){1,7}|:)addresses starting with ::, including :: on its own
02

What it accepts and rejects

Every sample below is checked automatically in JavaScript and Python. The tester above is preloaded with all of them, one per line.

Should match
Should match
2001:0db8:85a3:0000:0000:8a2e:0370:7334✓
2001:db8::8a2e:370:7334✓
::1✓
::✓
fe80::1✓
2001:db8::✓
Should not match
Should not match
2001:db8::85a3::7334✗
1:2:3:4:5:6:7:8:9✗
12345::1✗
gggg::1✗
192.168.1.1✗
:1:2:3:4:5:6:7✗
03

Copy it into your code

RE2-safeNo lookarounds or backreferences, so the same pattern works in Go's RE2 engine and in Rust's regex crate.

const ipv6Re = /^(?:(?:[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}|:))$/;

export function isValidIpv6(value) {
  return ipv6Re.test(value.trim());
}
04

When not to use regex for this

Parse IPv6 with your language's IP library (net/netip in Go, ipaddress in Python, a library in JavaScript). It handles zone IDs, embedded IPv4 and canonical formatting, and the code reads better than this pattern.

05

Questions engineers actually ask

Why is the IPv6 regex so long?
The :: shorthand can replace a run of zero groups anywhere, and each position needs its own alternative so that :: appears at most once.
Does it accept ::ffff:192.168.1.1?
No. IPv4-mapped addresses need an extra branch; use an IP parsing library if you expect them.
What is catastrophic backtracking?
Some patterns, usually nested quantifiers like (a+)+, make a backtracking engine try an exponential number of paths on input that almost matches. The tester stops any run after 300ms, so a bad pattern can't freeze your tab. In production, that same pattern can take down a server (a ReDoS attack).
06

More web patterns

07

More from the workbench

Fine print

Tools: on the house.
Engineer: by the hour.

The regex was free. Code that doesn't need one is the upgrade: typed schemas, validated once at the edge, trusted everywhere after.

I'm Himanshu, an AI and full-stack engineer. I build MVPs, AI agents and the growth plumbing around them for early-stage startups.