wiki / systems
content addressing and cids
What a CID is made of, why CIDv1 exists, and what content addressing does and doesn't give you.
updated · 4 min read
A location address says where data lives: a URL, a disk sector, a path on a server. A content address says what the data is, derived from its bytes with a cryptographic hash. Ask for the content address and anyone who has the bytes can serve them, because you can check what you got. In IPFS and IPLD that address is a CID.
anatomy of a CID
A CID is a typed content address: which version, what kind of data, and a self-describing hash of it. It is built from three multiformats.
- multihash: a hash prefixed with which function produced it and how long the digest is, so
sha2-256andblake3can coexist. - multicodec: a code for how to interpret the bytes once fetched, such as
raw(0x55),dag-pb(0x70), ordag-cbor(0x71). - multibase: a one-character prefix saying how the binary CID was encoded into text. Only used in the string form.
binary: <cid-version varint> <content multicodec varint> <multihash>
string: <multibase prefix> + base-encode(binary)
b afyb... b = base32, then version 1, dag-pb, sha2-256 digest
^ ^
| +-- encoded CID bytes
+----- multibase prefix
CIDv0 and CIDv1
CIDv0 is the original form: a bare base58btc multihash. Everything else is implicit. The base is always base58btc, the codec always dag-pb, the hash always a 32-byte sha2-256. If a string is 46 characters and starts with Qm, it’s CIDv0.
CIDv1 writes the version and codec explicitly and adds the multibase prefix, so it can address any codec, use any hash, and be encoded in any base. The default string encoding is case-insensitive base32 (the bafy... strings), which fits in a DNS label for subdomain gateways. For IPNS names, base36 is encouraged because it’s shorter.
Converting with Kubo’s CLI:
$ ipfs cid format -v 1 -b base32 QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR
bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi
Going back to v0 only works for dag-pb CIDs, since v0 can’t express any other codec. The CID inspector breaks any CID into its parts in the browser.
CIDs are not file hashes
Run sha256sum on a file and compare it with the digest inside its CID. They won’t match. Adding a file to IPFS does three things first:
- Chunking: large files are split into blocks, typically 256 KiB to 1 MiB.
- Structuring: the blocks become a Merkle DAG. UnixFS, encoded as
dag-pb, is the default layout for files and directories. - Encoding: the codec wraps each node with structure metadata.
The CID hashes the root block, which links to the rest. The one exception: a file that fits in a single block, added with the raw codec (--raw-leaves), has a multihash equal to the plain file hash.
The same bytes can produce different CIDs if any of these change: chunk size, DAG layout (balanced vs trickle), codec, CID version, or hash function. If you need reproducible CIDs across tools, pin those settings down.
what you get
- Verifiable retrieval. Every block is checked against its CID on arrival. A malicious or broken peer can withhold data, but it can’t hand you the wrong bytes without detection.
- Deduplication. Identical content added with identical settings yields identical CIDs, and identical blocks are stored once. Content-defined chunkers such as Rabin or Buzhash make it more likely that a small edit only changes a few blocks.
- Location independence. Any node, gateway, or cache holding the block can serve it.
what you don’t get
- Mutability. Change one byte and the CID changes. For a stable name you need a pointer. In IPFS that’s IPNS: a name derived from the hash of a public key, pointing at an
/ipfs/<cid>path through a record that carries an expiry, a sequence number, and a signature from the matching private key. Anyone can verify the record. Records in the DHT expire after 48 hours, so publishers must keep republishing. - Discovery. A CID says nothing about who has the data. IPFS nodes find providers through a Kademlia-based DHT; the public one is called Amino. Provider records have to be published and refreshed too.
- Availability. Content addressing doesn’t keep anything online. If no node pins the blocks, the CID still exists and the data doesn’t.