IPv6 Expander & Compressor

Expand or compress any IPv6 address to the RFC 5952 canonical form, plus the two compression rules that implementations get wrong.

The canonical form is the one RFC 5952 specifies, which is the one to store and compare. Nothing is uploaded.

One address, many spellings

These 5 strings are all the same 128 bits and all different text. That is fine until something compares two addresses as strings — a log filter, an access list, a cache key — at which point the same host stops matching itself.

Written asCanonical
2001:0db8:0000:0000:0000:0000:0000:0001 2001:db8::1
2001:db8:0:0:0:0:0:1 2001:db8::1
2001:DB8::1 2001:db8::1
2001:db8::0:1 2001:db8::1
2001:db8::1 2001:db8::1

The two rules everyone gets wrong

Suppressing leading zeros and lower-casing are easy. The other two are not: :: replaces the longest run of zero groups and breaks ties toward the first, and it must not be used for a run of only one group.

InputCanonicalRule
2001:0db8:0000:0000:0000:0000:0000:0001 2001:db8::1 leading zeros go, the run collapses
2001:DB8::AB 2001:db8::ab hex is lower case
2001:db8:0:0:1:0:0:1 2001:db8::1:0:0:1 a tie goes to the FIRST run
2001:db8:0:1:1:1:1:1 2001:db8:0:1:1:1:1:1 a single zero group is written out
0:0:0:0:0:0:0:0 :: all zeros is just ::
0:0:0:0:0:0:0:1 ::1 loopback
2001:db8:0:0:0:1:0:0 2001:db8::1:0:0 the longest run wins, not the last
fe80:0:0:0:0:0:0:0 fe80:: a trailing run collapses too

A compressor that greedily shortens any zero run produces a legal address that is not the canonical one — and two such strings will not match each other. That is why the rules are written down rather than left to taste.

128 bits do not fit in a number

A JavaScript number is a double, which carries 53 bits of integer precision. Two to the 128 minus one and two to the 128 are the same double, so any arithmetic on a full address near the top of the space silently collides. Everything here uses BigInt, and the all-ones address comes out as exactly 2¹²⁸ − 1.

PrefixAddresses
/32 79228162514264337593543950336
/48 1208925819614629174706176
/56 4722366482869645213696
/64 18446744073709551616
/128 1

A single /64 — the usual size handed to one network segment — holds more addresses than the entire IPv4 space squared. Which is the actual reason subnetting IPv6 works differently: there is no pressure to size a block to its host count, so the arithmetic that dominates IPv4 planning simply does not arise.

What gets rejected

Malformed input is refused rather than guessed at. Two :: runs are ambiguous — there is no way to know how many groups belong to each — so they are rejected outright, as is a :: that would stand for no groups at all.

2001::db8::1
(empty)
xyz::1
12345::
1:2:3:4:5:6:7
1:2:3:4:5:6:7:8:9
:::

How to use

  1. Paste an IPv6 address in any spelling.
  2. Read the canonical form and the fully expanded one.
  3. See which zero run the :: is standing for.
  4. Malformed input is rejected rather than guessed at.

Frequently asked questions

Why does the same address have several spellings?

Because IPv6 text form allows leading zeros to be dropped or kept, hex in either case, and a run of zero groups to be replaced by a double colon. All of those parse to the same 128 bits, which is fine until something compares two addresses as strings — a log filter, an access list, a cache key.

What is the canonical form?

The one RFC 5952 specifies: leading zeros suppressed, hex in lower case, and the double colon placed by a fixed rule. Storing and comparing that form is what stops the same host failing to match itself.

Where does the double colon go?

On the longest run of zero groups, and on a tie it takes the first one. So 2001:db8:0:0:1:0:0:1 has two runs of two and canonicalises to 2001:db8::1:0:0:1 rather than 2001:db8:0:0:1::1.

Can it replace a single zero group?

No, and this is the rule most often missed. A run of exactly one zero group must be written out, so 2001:db8:0:1:1:1:1:1 stays as it is. Compressing it produces a legal address that is not the canonical one, and the two will not match each other as strings.

Why are two double colons rejected?

Because they are ambiguous. There is no way to know how many zero groups belong to each, so the address has no single meaning and is refused rather than guessed at. The same goes for a double colon that would stand for no groups at all.

Why does IPv6 arithmetic need BigInt?

Because 128 bits do not fit in a JavaScript number, which carries 53 bits of integer precision. Two to the 128 minus one and two to the 128 are the same double, so any address near the top of the space would silently collide with its neighbours.

How big is a /64?

Larger than the entire IPv4 address space squared. That is why IPv6 subnetting works differently in practice: there is no pressure to size a block to its host count, so the arithmetic that dominates IPv4 planning simply does not arise.

Does this send anything anywhere?

No. Everything is computed in your browser, and nothing is uploaded.

🔒 This tool runs entirely in your browser. Nothing you enter is uploaded, logged, or stored.