IPNS URI (ipns://)

status: reliable
History
Commit History
Feedback
GitHub ipfs/specs (inspect source, open issue)

The ipns:// URI scheme names mutable pointers. It is the mutable sibling of the ipfs:// scheme, and shares its structure, syntax, origin model, and its deferral of path, query, and fragment handling to the WHATWG URL parser. This document defines only what is specific to ipns://: what its content root may contain, and how that root is resolved.

Read ipfs:// first: it defines everything the two schemes share, including the authority form and why // is required, the origin model, path, query, and fragment behavior, the ban on endpoint information, and the shape of the IANA registration. This document does not repeat it.

1. What is it?

An ipns:// URI places a mutable content root in the authority and an optional path after it:

ipns://{ipns-name}/{path}?{query}#{fragment}

For example:

ipns://k51qzi5uqu5dlvj2baxnqndepeb86cbk3ng7n3i46uzyxzyqj2xjonzllnv0v8/
ipns://dnslink.example.net/wiki/

ipns://{ipns-name}/{path} maps to the content path /ipns/{ipns-name}/{path}.

Because the target of an IPNS name can be republished to point at different content over time, an ipns:// URI is a mutable pointer. ipns:// MUST NOT be used as a namespace for a bare CID that directly names immutable bytes: such a CID belongs under ipfs://. The only CIDs valid under ipns:// are those that name a public key, libp2p-key CIDv1s today: a key is a mutable pointer to content, where a bare content CID is not (see The content root).

2. The content root

ipns:// supports two kinds of content root, and every implementation MUST accept both:

They are told apart by trying the first and falling back to the second: an implementation attempts to parse the authority as a CIDv1, and only if that fails does it treat the authority as a DNSLink domain. Parsing the authority gives the exact steps.

ipns-URI       = "ipns://" ipns-authority path-abempty
                 [ "?" query ] [ "#" fragment ]

ipns-authority = ipns-key / dnslink-name

; (a) IPNS Name: a CIDv1 naming a public key, multibase base36
;     (libp2p-key, 0x72, is the codec in use today)
ipns-key       = "k" 1*base36char   ; canonical form; see "Cryptographic key form"
                                    ; for other case-insensitive encodings
                                    ; a single DNS label, no "."
                                    ; SHOULD NOT exceed 63 characters total
base36char     = %x30-39 / %x61-7A  ; "0"-"9" / "a"-"z"

; (b) DNSLink name: an ICANN-compatible DNS name, at least one "." on the public internet
dnslink-name   = label 1*( "." label )
label          = let-dig [ *61( let-dig / "-" ) let-dig ]  ; RFC 1123: max 63 characters,
                                                           ; no leading or trailing "-"
let-dig        = %x61-7A / %x30-39                         ; lowercase; DNS comparison
                                                           ; is case-insensitive

As in ipfs://, the ABNF describes the canonical form only: a base36 key. A key in another case-insensitive multibase does not match ipns-key but can still appear as input; Cryptographic key form says how to handle it.

path-abempty, query, and fragment are as in ipfs://. The same WHATWG-URL-governs tie-breaker applies.

2.1 Cryptographic key form

2.3 Parsing the authority

The key form is tried first and the DNSLink form is the fallback. The order is what makes the two unambiguous in the one place they could collide, a dot-less authority: a canonical ipns-key is a single label with no dot, and a public DNSLink name always has at least one. A resolver MUST apply these steps in order.

  1. Try the key form. Parse the authority as a CIDv1. If it decodes to a CID that satisfies Cryptographic key form, it is an IPNS Name: resolve it as a key and stop. If it decodes to a CID whose codec the implementation does not support, reject or redirect per that section, and stop.
  2. Fall back to DNSLink. If the CIDv1 parse failed and the authority contains a ., treat it as a DNSLink name and resolve it per DNSLink name form, then stop.
  3. Try the inlined label. Otherwise the authority is a single label that is not a key. A resolver SHOULD decode it with the Subdomain Gateway's DNSLink label encoding and retry step 2 with the result, which is what lets an inlined label round-trip back into a dotted name (see Resolution).
  4. Otherwise reject the authority as unresolvable, as in ipfs://. Implementations SHOULD present an error explaining why, rather than forwarding the name to a resolver that can only fail.

A DNSLink name is never mistaken for a key, because a dotted name cannot decode as a CIDv1 and a key never contains a dot. Trying the key form first also means a name that would decode as a CID is always read as a key, which is what keeps one identifier from resolving two different ways in two different implementations.

Step 3 is also where a local-resolver extension for dot-less names would sit. Such names are out of scope for public-internet ipns:// URIs, because they are network-relative: the same origin string can name different content on different networks. Origin-scoped state (storage, permissions) sandboxed under such a name can therefore leak between unrelated sites, so an implementation offering the extension SHOULD account for the instability, for example by not persisting that state.

3. Resolution

Resolution has one step that ipfs:// does not. The content root is mutable, so it MUST first be resolved to an immutable CID: an IPNS Name through its signed record, a DNSLink name through DNS, which may itself point at another DNSLink name or at an IPNS Name before it bottoms out. Everything after that is identical to ipfs://. The CID that comes out is the content root for the rest of the operation, and its multicodec is what says how to decode the root block and how to walk {path} out of it, exactly as in ipfs://. Only the step that produces the CID differs; the traversal does not.

Otherwise resolution follows ipfs://, with the IPNS namespace in place of the IPFS one: ipns://{ipns-name}/{path} is retrieved as the content path /ipns/{ipns-name}/{path}, for example through a Subdomain Gateway request to https://{ipns-name}.ipns.example.net/{path} when an isolated origin is required.

A DNSLink name cannot appear in a subdomain as-is: its dots would create extra DNS levels and break wildcard TLS, so the Subdomain Gateway inlines the name into a single label, turning ipns://dnslink.example.net into https://dnslink-example-net.ipns.example.net. Each . becomes a -, and any - already in the name is doubled, so ipns://my-site.example.net inlines to my--site-example-net. Step 3 of Parsing the authority is what lets that inlined label come back the other way. The canonical ipns:// URI always uses the original dotted name, never the inlined label, so an implementation SHOULD normalize an inlined label back to its dotted form before rendering the URI or deriving its origin.

When the content root is a cryptographic key, a resolver MUST validate the IPNS record's signature as defined by [ipns-record]. When it is a DNS name, DNSLink resolution applies, including its recursion bound (see DNSLink name form).

4. Notes for implementers

This section is non-normative.

4.1 Why base36 for Ed25519

A single DNS label is capped at 63 characters, and an authority that should double as a subdomain-gateway label inherits that cap. Because an Ed25519 key is inlined rather than hashed (see Keys too big to inline), its libp2p-key CIDv1 is 40 bytes, the largest an IPNS name gets in practice. That is 65 characters in base32, two over the limit, and 63 in base36 (k51...), which just fits. base32 remains fine for the shorter, hashed names, but base36 is what keeps an Ed25519 IPNS name usable as an authority and as a Subdomain Gateway label.

4.2 Room for new key types

In practice an IPNS name today is a libp2p-key (0x72), which wraps the public key in a libp2p protobuf. Post-quantum signature schemes are expected to change that, either as new key types carried inside that same wrapper, which leaves the authority untouched, or under self-describing key container codecs that drop the libp2p wrapper altogether. Both directions are tracked in ipfs/kubo#11281.

The codec rule in Cryptographic key form is written to survive that: it names no fixed set and leaves each implementation to say which codecs it accepts. What does not change is the shape of the authority, a case-insensitive CIDv1 that fits a DNS label. Post-quantum public keys are far too large to inline, so their names will be digests rather than keys, with the consequences described in Keys too big to inline.

4.3 Keep the whole resolution chain

An ipns:// address resolves through layers: a DNSLink name points at an IPNS Name or directly at a CID, and an IPNS Name resolves to a CID. An application that saves an address, as a bookmark or before pinning, benefits from recording every layer it resolved through: the DNS name, the IPNS Name behind it, and the CID at save time. Each layer answers a different question later: the DNS name is the human-readable origin, the IPNS Name fetches the latest content from the same publisher even if the domain lapses, and the CID retrieves the exact saved version for as long as anyone keeps it available.

4.4 Keys too big to inline

An IPNS Name is a multihash of the serialized public key, so how big that key is decides what the name actually carries.

The second case produces the shorter name, not the longer one: about 57 characters in base36 against 63 for an inlined Ed25519 key. The 63-character DNS label limit is a constraint on inlined keys, and it does not bite here.

What does bite is that the key cannot be recovered from the name, so a resolver has to obtain it some other way before it can check a signature. Records for such keys carry a serialized copy of the public key alongside the signature, and a resolver MUST confirm that the copy hashes back to the authority before trusting it ([ipns-record]). Because the authority is exactly the hash of those key bytes, the key is itself content-addressed: it can be stored and fetched as immutable data under the same multihash rather than travelling in every record.

5. IANA considerations

ipns is registered as a provisional URI scheme under the procedure of [rfc7595]: IANA provisional registration for ipns. That registration is the authoritative record of the scheme name, status, applications, and change controller; this document does not repeat them. The considerations are as for ipfs://, with these additions:

A. References

[cid]
CID (Content IDentifier). Juan Benet; Marcin Rataj; Robin Berjon. 2026-06-26. URL: https://specs.ipfs.tech/cid/
DNSLink Gateway Specification. Marcin Rataj; Thibault Meunier. 2022-11-09. URL: https://specs.ipfs.tech/http-gateways/dnslink-gateway/
[ipns-record]
IPNS Record and Protocol. Vasco Santos; Steve Allen; Marcin Rataj; Henrique Dias; Gus Eggert. 2025-02-28. URL: https://specs.ipfs.tech/ipns/ipns-record/
[rfc2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[rfc7595]
Guidelines and Registration Procedures for URI Schemes. D. Thaler, Ed.; T. Hansen; T. Hardie. IETF. June 2015. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc7595
[subdomain-gateway]
Subdomain Gateway Specification. Marcin Rataj; Adrian Lanzafame; Vasco Santos; Oli Evans; Thibault Meunier; Steve Loeppky. 2025-04-03. URL: https://specs.ipfs.tech/http-gateways/subdomain-gateway/

B. Acknowledgments

We gratefully acknowledge the following individuals for their valuable contributions, ranging from minor suggestions to major insights, which have shaped and improved this specification.

Editor
Marcin Rataj (Interplanetary Shipyard) GitHub
Special Thanks
Frédéric Wang (Igalia) GitHub
Jonny Crunch GitHub
Dietrich Ayala GitHub
bumblefudge GitHub