IPFS URI (ipfs://)

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

The ipfs:// URI scheme names immutable content by its CID ([cid]). An ipfs:// URI is a native address that a browser-like application can open directly, without hard-coding an HTTP gateway. It is one half of native IPFS addressing; the mutable half is the ipns:// scheme.

1. What is it?

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

ipfs://{cid}/{path}?{query}#{fragment}

For example:

ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/wiki/Vincent_van_Gogh.html#some-fragment
ipfs://bafybeietjm63oynimmv5yyqay33nui4y4wx6u3peezwetxgiwvfmelutzu/subdir/hello.txt?filename=index.html

The authority ({cid}) is a self-describing content address. Because a CID is derived from the bytes it names, the data behind an ipfs:// URI can never change: the same URI always resolves to the same content, and any resolver can verify it received exactly those bytes.

For this reason, an ipfs:// URI MUST address only immutable, content-addressed data. A pointer whose target its owner can update later (a cryptographic IPNS name or a DNSLink name) is mutable and MUST NOT be placed under ipfs://; it belongs under ipns:// instead.

2. Syntax

An ipfs:// URI always uses the authority form: the // is required. The ABNF below describes it; rules named but not defined here (pct-encoded, segment, query, fragment) come from [rfc3986].

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

ipfs-authority = cidv1-base32       ; canonical authority form; see "What the authority
                                    ; may contain" for other case-insensitive encodings

cidv1-base32   = "b" 1*base32char   ; multibase 'b': RFC4648 base32, lowercase, no padding
                                    ; MUST decode to a valid CIDv1
base32char     = %x32-37 / %x61-7A  ; "2"-"7" / "a"-"z"

path-abempty   = *( "/" segment )   ; RFC 3986, Section 3.3

The ABNF describes the canonical form only: an authority that is a base32 CIDv1. A URI whose authority uses another case-insensitive multibase does not match this grammar but can still appear as input; What the authority may contain says how to handle it: normalize to base32, or reject.

An ipfs:// URI is a URL as defined by the WHATWG URL Standard. The ABNF above is descriptive; when it and the WHATWG parser disagree, the WHATWG parser wins, because this scheme exists to behave well in browsers. This tie-breaker applies throughout this document.

3. Authority

In the WHATWG URL Standard, the component after // is the URL's authority. An ipfs:// URI is read the same way: its authority is the content root, a single CID. Reading ipfs://{cid}/{path} as a URL is what lets the CID define an Origin and anchor a relative path.

The // is required. Neither ipfs nor ipns is a special scheme, so without // there is no authority, and without an authority there is nothing to attach a stable origin to. The opaque ipfs:{cid} form has neither; producers MUST NOT emit it. Reading ipfs:// as a WHATWG URL shows how the two forms parse.

3.1 What the authority may contain

An authority that neither satisfies these rules nor can be normalized to canonical base32 under them MUST be rejected as unresolvable. Implementations SHOULD show an error explaining why the address cannot work instead of forwarding the URI to a resolver or gateway that can only fail.

3.2 Origin

The content root defines the security context of the content it names, mirroring the Subdomain Gateway origin model: ipfs://{cid}/{path} and https://{cid}.ipfs.example.net/{path} name the same content under the same origin model, where the CID is the origin-defining label.

On its own, the WHATWG URL Standard gives every non-special URL, ipfs:// included, a new opaque origin on each parse. That alone does not give the property this scheme needs: same CID, same origin; different CID, different origin. To get it, an implementation SHOULD derive the origin from the scheme and the content root alone, so that the content root is the only thing the origin depends on.

How that origin is serialized is left to the implementation, because it depends on what the host environment can be made to express. Two forms are known to work:

Either way the origin is keyed on the authority string, which browsers and other agents use to sandbox JavaScript storage (localStorage, IndexedDB, Cache Storage) and to scope API permissions. Two encodings of the same CID are two different strings, and therefore two different origins with separate storage and permissions. Normalizing the authority to canonical base32 keeps each content root in a single security context under either serialization.

4. Path, query, and fragment

4.1 How the content root drives traversal

A CID is self-describing, and its multicodec is what tells a resolver both how to decode the block the CID addresses and how to walk {path} out of that block. Nothing in the URI selects this behavior, and nothing needs to: the codec in the content root does.

Other codecs follow the same rule: a resolver walks {path} only as far as the codec defines links, so a codec with no links, or one the resolver does not recognize, leaves a non-empty path unresolvable.

This applies at every step, not only the first. Each link the traversal follows carries its own CID with its own codec, so the rules can change partway down a path: a dag-cbor root can link to a dag-pb node, after which the remaining segments are UnixFS names. Path Gateway ([path-gateway]) defines the traversal itself, including how an unresolvable path is reported.

5. Resolution

To resolve an ipfs:// URI, an implementation builds the content path /ipfs/{cid}/{path} and retrieves it through any IPFS retrieval mechanism: for example, a Path Gateway request to https://example.net/ipfs/{cid}/{path}, or a Subdomain Gateway request to https://{cid}.ipfs.example.net/{path} when an isolated origin is needed. The query is carried through; the fragment stays client-side.

A resolver that retrieves blocks itself, over a Trustless Gateway ([trustless-gateway]) or a peer-to-peer transport, MUST verify them: hash every block it receives and walk the DAG from the content root, so that each block on the path is accounted for. Verification is what lets an ipfs:// URI be trusted regardless of where the bytes came from.

Retrieval through a trusted Path or Subdomain Gateway is the exception: the gateway performs that verification and the client takes its word for it. An implementation that resolves ipfs:// this way SHOULD make the gateway it trusts visible to the user, because the immutability guarantee then rests on that gateway rather than on the URI.

A native ipfs:// implementation SHOULD resolve content paths with the same semantics as a Path Gateway, so that the same URI resolves consistently whether it is opened by a native handler or handed to a gateway. In a browser-like context, a native implementation SHOULD also mirror the origin isolation that a Subdomain Gateway provides, giving each content root its own origin, derived from the scheme and that root alone. Origin describes the two serializations known to work.

6. Notes for implementers

This section is non-normative: it explains the reasoning behind the rules above and adds no new requirements.

6.1 Reading ipfs:// as a WHATWG URL

The // is what makes the content root an authority. Neither ipfs nor ipns is a special scheme, and the two forms (with and without the //) parse very differently:

Only a form with an authority can be given a stable origin, which is why the authority form is required and the opaque ipfs:{cid} form is not used to address content.

6.2 Why the authority must be case-insensitive

A CIDv0 is base58btc, whose alphabet is case-sensitive and contains uppercase letters. An authority is not a safe place for it, for two independent reasons:

  1. Any engine that treats ipfs as a special scheme parses the authority as a domain via domain to ASCII, which case-folds ASCII uppercase to lowercase. A lowercased base58btc string is a different, invalid CID. Percent-encoding cannot rescue it, because % is itself a forbidden domain code point.
  2. Even when they do not, deployed browsers and other user agents force-lowercase URL authorities before any resolver sees them.

base32 avoids both: its alphabet is all-lowercase and contains no forbidden code point, so it survives every parse unchanged. The same case-folding applies to a Subdomain Gateway label ({cid}.ipfs.example.net), which additionally caps the root at 63 characters (the DNS label limit), so only a case-insensitive CIDv1 that fits a label can serve as both an authority and a stable origin on the public web. This is why case-insensitivity is a correctness and security property, not a stylistic preference.

CIDv0 stays safe in any position that is not an authority, such as a path segment.

6.3 Normalizing the authority

The rules in What the authority may contain describe two normalization paths that end in the same place, canonical base32, for two different reasons:

In both cases, normalize (or redirect to the normalized URI) before computing an origin or issuing a request.

6.4 Roots longer than 63 characters

A CIDv1 with a large multihash, sha2-512 being the common case, produces a base32 string longer than 63 characters. Such a root cannot become a DNS label, so Subdomain Gateway deployments that rely on public DNS and wildcard TLS certificates cannot serve it and respond with HTTP 400; representing such CIDs there remains an open question.

The limit is specific to those PKI/TLS deployments. A localhost subdomain gateway ({cid}.ipfs.localhost) or a native ipfs:// implementation is not bound by it: *.localhost subdomains are resolved locally rather than through public DNS, and browsers treat them as a secure context without TLS certificates. Per What the authority may contain, long roots are best kept to internal use; on the public web, sha2-256 remains the safe default.

7. IANA considerations

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

This specification supplies what the provisional registration leaves open:

A. References

[cid]
CID (Content IDentifier). Juan Benet; Marcin Rataj; Robin Berjon. 2026-06-26. URL: https://specs.ipfs.tech/cid/
[path-gateway]
Path Gateway Specification. Henrique Dias; Marcin Rataj. 2026-03-05. URL: https://specs.ipfs.tech/http-gateways/path-gateway/
[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
[rfc3986]
Uniform Resource Identifier (URI): Generic Syntax. T. Berners-Lee; R. Fielding; L. Masinter. IETF. January 2005. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc3986
[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/
[trustless-gateway]
Trustless Gateway Specification. Henrique Dias; Marcin Rataj; Héctor Sanjuán; Adin Schmahmann. 2026-03-05. URL: https://specs.ipfs.tech/http-gateways/trustless-gateway/
[unixfs]
UnixFS. Hugo Valtier; Marcin Rataj. 2026-03-05. URL: https://specs.ipfs.tech/unixfs/

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
Jonny Crunch GitHub
Dietrich Ayala GitHub
Frédéric Wang (Igalia) GitHub
bumblefudge GitHub