IPv6 Compression and Expansion

Shorten an IPv6 address to its one canonical form or expand it to all 32 digits, and see which zeros go, why one run became :: and which RFC 5952 rule your typing broke. Lists work too.

RFC 5952 canonical text · RFC 4291 parsing, mixed IPv4 tails included · runs in your browser

Read as IPv6

The 8 groups, and what compression dropsCharacters: 39 → 17 · 22 characters fewer
keptleading zero, droppedthe run that becomes ::other zeros, kept
Try

One address, or a list with one per line (up to 100). Converted in your browser; nothing is sent.

3 rules appliedRFC 5952

2001:db8::1:0:0:1

Two runs of 2 zero groups: the first became ::

RFC 5952, rule by rule

Leading zeros dropped§4.1Fixed0DB8 → db8, 0001 → 1, 0000 → 0, 0000 → 0
:: as long as possible§4.2.1Fixed0000:0000 written out → ::
No :: for one group§4.2.2Passed
Longest run, first on a tie§4.2.3PassedTwo runs of 2 zero groups: the first became ::
Lowercase§4.3Fixed0DB8 → db8
Compressed (RFC 5952)
Expanded (full)
In a URL
As a number
Decimal · hex · binary
Reverse DNS name

How do you compress an IPv6 address?

Lowercase it, drop the leading zeros in each group, then replace the longest run of two or more all-zero groups with ::, the first run if two are equally long.

That gives the one canonical form RFC 5952 asks software to print. Programs must still accept every other valid spelling as input, so compressing never changes the address, only how it is written.

2001:0DB8:0000:0000:0000:FF00:0042:8329 shortened to 2001:db8::ff00:42:8329, step by step.
IPv6 compression tool showing the zeros RFC 5952 drops and the run that becomes ::IPv6 compression tool showing the zeros RFC 5952 drops and the run that becomes ::What you typedUppercase, leading zeros and all: any valid spelling is read.Dropped zerosLeading zeros struck out, group by group.The run that becomes ::The longest run of zero groups; on a tie, the first.Runs that stayOther zero runs keep their 0s, with the reason.Rule by ruleHow many RFC 5952 rules the typing broke; the checklist under it names each one and what changed.
Two equal runs of zeros: RFC 5952 compresses the first, and the checklist names each rule the typing broke.

What are the IPv6 compression rules?

RFC 5952 sets five rules: drop leading zeros, make :: as long as possible, never use :: for a single zero group, compress the longest run (the first on a tie), and write hex letters in lowercase.

A sixth recommendation covers addresses that carry IPv4: after a prefix such as ::ffff:, write the last 32 bits as a dotted IPv4 address. The tool checks each rule against what you typed and names the ones it fixed.

1Leading zeros dropped§4.1

Right: 2001:db8::1

Wrong: 2001:0db8::0001

2:: as long as possible§4.2.1

Right: 2001:db8::2:1

Wrong: 2001:db8:0:0:0:0:2:1

3No :: for one group§4.2.2

Right: 2001:db8:0:1:1:1:1:1

Wrong: 2001:db8::1:1:1:1:1

4Longest run, first on a tie§4.2.3

Right: 2001:db8::1:0:0:1

Wrong: 2001:db8:0:0:1::1

5Lowercase§4.3

Right: 2001:db8::a

Wrong: 2001:DB8::A

+Dotted IPv4 tail§5

Right: ::ffff:192.0.2.1

Wrong: 0:0:0:0:0:ffff:192.0.2.1

Each rule with RFC 5952's own right and wrong examples.

How do you expand an IPv6 address?

Count the groups that are written, let :: stand for as many zero groups as it takes to reach eight, and pad every group to four digits: 2001:db8::1 has three groups, so :: is five.

The expanded form is what reverse DNS uses, nibble by nibble, and what many logs and spreadsheets need for sorting as text. Python calls it .exploded and Go StringExpanded.

2001:db8::1 expanded: 3 written groups, 5 zero groups for ::, every group padded.

How many ways can one IPv6 address be written?

Many: leading zeros, letter case and the place of :: can all change, so one address has many valid spellings, and RFC 5952 lists eight for 2001:db8:0:0:1:0:0:1 before fixing one canonical form.

That is why comparing addresses as text fails: two spellings of the same address don't match. Compare them as 128-bit numbers instead, or compress both first.

2001:db8:0:0:1:0:0:12001:0db8:0:0:1:0:0:12001:db8::1:0:0:12001:db8::0:1:0:0:12001:0db8::1:0:0:12001:db8:0:0:1::12001:db8:0000:0:1::12001:DB8:0:0:1::1
2001:db8::1:0:0:1canonical · RFC 5952
Eight spellings from RFC 5952, one address.

How do you write an IPv6 address in a URL, with a port or a zone?

Put the address in square brackets, http://[2001:db8::1]:8443/, so the port can't be mistaken for a group; a zone such as %eth0 can't go in a browser URL at all.

RFC 5952 says to bracket an address that has a port, and calls 2001:db8::1:8443 not recommended. Brackets are used for nothing else in a URL. Browsers print the address in hex even after ::ffff:, so [::ffff:192.0.2.1] shows as [::ffff:c000:201].

Zones name an interface on one machine, as in fe80::1%eth0. RFC 9844 took them back out of URLs in 2025 and browsers refuse them, though programs should still let you type one.

http://scheme[2001:db8::1]IPv6 in brackets:8443port/statuspath

A zone (%eth0) · fe80::1%eth0

Typed in a program's fieldallowed
In a browser URLrefused
inet_pton()can't parse it
Global addressesnever have one
A URL with an IPv6 address taken apart, and where a zone may go.

How do I compress or expand IPv6 in code?

Parse the address and print it: Python's .compressed, Go's netip.Addr.String() and MySQL's INET6_NTOA(INET6_ATON(…)) give the canonical text, and .exploded and StringExpanded() the full form.

Python's str() is the compressed form too, and Python accepts a %zone suffix. MySQL prints lowercase, at most 39 characters, the same on every platform.

› import ipaddress
a = ipaddress.ip_address('2001:0DB8::0001')
a.compressed, a.exploded
('2001:db8::1', '2001:0db8:0000:0000:0000:0000:0000:0001')

Python ipaddress

› a := netip.MustParseAddr("2001:0DB8::0001")
fmt.Println(a.String(), a.StringExpanded())
2001:db8::1 2001:0db8:0000:0000:0000:0000:0000:0001

Go net/netip

› SELECT INET6_NTOA(INET6_ATON('2001:0DB8::0001'));
2001:db8::1

MySQL 8.4

The canonical short form and the full form from Python, Go and MySQL.

Frequently asked questions

What is the compressed form of 2001:0db8:0000:0000:0000:ff00:0042:8329?

It is 2001:db8::ff00:42:8329. Lowercase the letters, drop each group's leading zeros (0db8 becomes db8, 0042 becomes 42), then replace the run of three all-zero groups with ::. The result is 22 characters instead of 39, and it is the only form RFC 5952 calls canonical. Expanding it again gives back exactly the same 32 hex digits.

Can :: be used twice in an IPv6 address?

No. :: stands for one or more groups of zeros and may appear only once; with two, nobody could tell how many zero groups each one stands for, so 2001:db8::1::1 is invalid. When an address has two runs of zeros, compress the longer one, or the first if they are equally long, and write the other run as 0:0, as in 2001:db8::1:0:0:1.

Why doesn't 2001:db8:0:1:1:1:1:1 compress to 2001:db8::1:1:1:1:1?

Because RFC 5952 forbids using :: for a single zero group. The shortening would save one character and make the address harder to read, so the canonical form keeps the lone group as 0: 2001:db8:0:1:1:1:1:1. Parsers still accept 2001:db8::1:1:1:1:1 as the same address, but software should never print it that way.

Should IPv6 addresses be uppercase or lowercase?

Lowercase. RFC 5952 requires the hex letters a to f in lowercase for the canonical form, and browsers and most libraries print them that way. Software must still accept uppercase input, so 2001:DB8::A and 2001:db8::a are the same address; only the printed form changes. Uppercase is common in older documentation and in some vendors' configuration files.

How do I expand :: in an IPv6 address?

Count the groups that are written, then let :: stand for as many zero groups as it takes to make eight. In 2001:db8::ff00:42:8329 five groups are written, so :: is three groups of 0000. Pad every group to four digits and you get 2001:0db8:0000:0000:0000:ff00:0042:8329, the expanded form that reverse DNS and many log tools use.

How many characters is the longest IPv6 address?

39 for the full hex form: eight groups of four digits and seven colons. The form with a dotted IPv4 tail can be longer, which is why the socket API's buffer size INET6_ADDRSTRLEN is 46 bytes, enough for 0000:0000:0000:0000:0000:ffff:255.255.255.255 and the terminating NUL. Compressed addresses are usually far shorter; the address :: is just two characters.

Why does ::ffff:c000:280 become ::ffff:192.0.2.128?

Because RFC 5952 recommends writing the last 32 bits of an IPv4-mapped address as a dotted IPv4 address, since that is what those bits mean. Both spellings are the same address and both are valid input. Browsers are the exception: the URL Standard always prints the hex form, so the same address appears as [::ffff:c000:280] in the address bar.

How do I put an IPv6 address with a port in a URL?

Put the address in square brackets and the port after them: http://[2001:db8::1]:8443/. Without brackets the port would look like one more group, which is why RFC 5952 says not to write 2001:db8::1:8443. Brackets are used only for IPv6 literals in URLs. A zone such as %eth0 can't go in a browser URL at all; browsers refuse it.

How do I compress an IPv6 address in Python?

Parse it with the ipaddress module and read .compressed for the canonical short form or .exploded for all 32 digits: ipaddress.ip_address('2001:0db8::0001').compressed gives '2001:db8::1', and str() returns the same. In Go, netip.Addr's String() and StringExpanded() do the same job, and MySQL's INET6_NTOA(INET6_ATON(…)) prints lowercase canonical text.

Can I compress a list of IPv6 addresses at once?

Yes. Paste up to 100 addresses, one per line, and the tool switches to a table with each line's compressed and expanded form and the RFC 5952 rules its spelling broke. Lines that aren't addresses are marked rather than dropped, so the rows still match your input. Copy either column or download a CSV; nothing leaves your browser.

Missing something?Suggest a feature or a new tool