⚠️️ (Note: this page is a work in progress; please improve it here) ⚠️️
Self-describing network addresses
Multiaddr is a format for encoding addresses from various well-established network protocols. It is useful to write applications that future-proof their use of addresses, and allow multiple transport protocols and addresses to coexist.
The current network addressing scheme on the internet is not self-describing. Traditional addresses leave much ambiguity. For example, it’s not always clear which transport protocol (TCP, UDP, or others) is being used. This ambiguity forces developers to write application-specific code that assumes a certain protocol, which causes “ossification”—rigid code that cannot easily adapt to future network protocols.
Consider the following traditional addresses:
127.0.0.1:9090 # IPv4. Is this TCP, UDP, or something else?
[::1]:3217 # IPv6. Is this TCP, UDP, or something else?
http://127.0.0.1/baz.jpg # Defaults to TCP port 80, but what if we wanted to use QUIC?
http://foo.com/bar/baz.jpg # Uses DNS resolution but defaults to TCP on port 80.
//foo.com:1234 # Ambiguous—what protocol does this address use after DNS resolution?
In these cases:
127.0.0.1:9090
could refer to either TCP or UDP, forcing developers to make assumptions.http://foo.com/bar/baz.jpg
) default to TCP, but there’s no flexibility for newer protocols like QUIC without making breaking changes to the application.Multiaddr solves this by providing self-describing addresses. Each part of the address specifies both the protocol and the network address, making it clear how to interact with the resource. This approach future-proofs applications, allowing them to adapt to new transport protocols.
/ip4/127.0.0.1/udp/9090/quic # IPv4 address using UDP on port 9090, with QUIC
/ip6/::1/tcp/3217 # IPv6 address using TCP on port 3217
/ip4/127.0.0.1/tcp/80/http/baz.jpg # IPv4 address using TCP on port 80, accessing an HTTP resource
/dns4/foo.com/tcp/80/http/bar/baz.jpg # DNS resolution (IPv4) using TCP on port 80, accessing an HTTP resource
/dns6/foo.com/tcp/443/https # DNS resolution (IPv6) using TCP on port 443 for HTTPS
In these examples:
/ip4/127.0.0.1/udp/9090/quic
specifies the use of UDP and QUIC, removing ambiguity./dns4/foo.com/tcp/80/http/bar/baz.jpg
clearly indicates that the address resolves to IPv4 via DNS and uses TCP to access an HTTP resource.By explicitly stating the protocol and transport, Multiaddr eliminates the assumptions that lead to network protocol ossification.
A multiaddr value is a recursive (TLV)+
(type-length-value repeating) encoding. It has two forms:
/ip4/127.0.0.1/udp/4023/quic
(this is the repeating part).
/
) (eg. /quic
and /ip4/127.0.0.1
)<addr-protocol-str-code>
is a string code identifying the network protocol. The table of protocols is configurable. The default table is the multicodec table.<addr-value>
is the network address value, in natural string form.Human-readable encoding (psuedo regex)
(/<addr-protocol-str-code>
/<addr-value>)
+
<addr-protocol-code>
is a variable integer identifying the network protocol. The table of protocols is configurable. The default table is the multicodec table.<addr-value>
is the network address value, of length L
.
Binary-packed encoding (psuedo regex)
(<addr-protocol-code>
<addr-value>)
+
These implementations are available:
import { multiaddr } from '@multiformats/multiaddr'
// Example 1: Simple IPv4 and UDP
const addr1 = multiaddr("/ip4/127.0.0.1/udp/1234")
// Multiaddr(/ip4/127.0.0.1/udp/1234)
console.log(addr1.bytes)
// <Uint8Array 04 7f 00 00 01 11 04 d2>
console.log(addr1.toString())
// '/ip4/127.0.0.1/udp/1234'
console.log(addr1.protos())
// [
// {code: 4, name: 'ip4', size: 32},
// {code: 273, name: 'udp', size: 16}
// ]
console.log(addr1.nodeAddress())
// {
// family: 4,
// port: 1234,
// address: "127.0.0.1"
// }
console.log(addr1.encapsulate('/sctp/5678').toString())
// '/ip4/127.0.0.1/udp/1234/sctp/5678'
// Example 2: IPv6 and TCP
const addr2 = multiaddr("/ip6/::1/tcp/8080")
// Multiaddr(/ip6/::1/tcp/8080)
console.log(addr2.bytes)
// <Uint8Array 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 90>
console.log(addr2.toString())
// '/ip6/::1/tcp/8080'
console.log(addr2.protos())
// [
// {code: 41, name: 'ip6', size: 128},
// {code: 6, name: 'tcp', size: 16}
// ]
console.log(addr2.nodeAddress())
// {
// family: 6,
// port: 8080,
// address: "::1"
// }
// Example 3: DNS and HTTPS
const addr3 = multiaddr("/dns4/example.com/tcp/443/https")
// Multiaddr(/dns4/example.com/tcp/443/https)
console.log(addr3.toString())
// '/dns4/example.com/tcp/443/https'
console.log(addr3.encapsulate('/p2p-circuit').toString())
// '/dns4/example.com/tcp/443/https/p2p-circuit'
import ma "github.com/multiformats/go-multiaddr"
// construct from a string (err signals parse failure)
m1, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
// construct from bytes (err signals parse failure)
m2, err := ma.NewMultiaddrBytes(m1.Bytes())
// true
strings.Equal(m1.String(), "/ip4/127.0.0.1/udp/1234")
strings.Equal(m1.String(), m2.String())
bytes.Equal(m1.Bytes(), m2.Bytes())
m1.Equal(m2)
m2.Equal(m1)
Why use Multiaddr instead of traditional addressing?
Multiaddr is designed to be future-proof, allowing easy adaptation to new protocols and network designs without breaking legacy applications. It removes ambiguity about what transport protocol or address family is being used.
How does Multiaddr handle new protocols?
The format is extensible. New protocols are simply added to the multicodec table. This allows Multiaddr to support emerging protocols without requiring changes to the core format.
What is the advantage of the binary-packed format?
The binary format is more compact and efficient for storage and transmission, especially useful in low-bandwidth or resource-constrained environments.
We will be submitting an RFC to the IETF. It will be worked on at the multiaddr repo.
The Multiaddr format was invented by @jbenet, and refined by the IPFS Team. It is now maintained by the Multiformats community. The Multiaddr implementations are written by a variety of authors, whose hard work has made future-proofing and upgrading hash functions much easier. Thank you!
The Multiaddr format (this documentation and the specification) is Open Source software, licensed under the MIT License and patent-free. The multiaddr implementations listed here are also Open Source software. Please contribute to make them great! Your bug reports, new features, and documentation improvements will benefit everyone.
Multiaddr is part of the Multiformats Project, a collection of protocols which aim to future-proof systems, today. Check out the other multiformats. It is also maintained and sponsored by Protocol Labs.