|
| 1 | +--- |
| 2 | +title: CID (Content IDentifier) |
| 3 | +description: > |
| 4 | + Self-describing content-addressed identifiers for distributed systems |
| 5 | +date: 2026-06-26 |
| 6 | +maturity: permanent |
| 7 | +editors: |
| 8 | + - name: Marcin Rataj |
| 9 | + github: lidel |
| 10 | + affiliation: |
| 11 | + name: Interplanetary Shipyard |
| 12 | + url: https://ipshipyard.com/ |
| 13 | + - name: Robin Berjon |
| 14 | + email: robin@berjon.com |
| 15 | + url: https://berjon.com/ |
| 16 | + github: darobin |
| 17 | + twitter: robinberjon |
| 18 | + affiliation: |
| 19 | + name: IPFS Foundation |
| 20 | + url: https://ipfsfoundation.org/ |
| 21 | +former_editors: |
| 22 | + - name: Juan Benet |
| 23 | + github: jbenet |
| 24 | +thanks: |
| 25 | + - name: Steven Allen |
| 26 | + github: Stebalien |
| 27 | + - name: Rod Vagg |
| 28 | + github: rvagg |
| 29 | + - name: bumblefudge |
| 30 | + github: bumblefudge |
| 31 | + - name: Volker Mische |
| 32 | + github: vmx |
| 33 | + - name: Joel Thorstensson |
| 34 | + github: oed |
| 35 | + - name: Oli Evans |
| 36 | + github: olizilla |
| 37 | + |
| 38 | +tags: ['data-formats'] |
| 39 | +order: 1 |
| 40 | +--- |
| 41 | + |
| 42 | +**CID** is a format for referencing content in distributed information systems, like [IPFS](https://ipfs.tech). |
| 43 | +It leverages [content addressing](https://en.wikipedia.org/wiki/Content-addressable_storage), |
| 44 | +[cryptographic hashing](https://simple.wikipedia.org/wiki/Cryptographic_hash_function), and |
| 45 | +[self-describing formats](https://github.com/multiformats/multiformats). |
| 46 | +It is the core identifier used by [IPFS](https://ipfs.tech) and [IPLD](https://ipld.io). |
| 47 | +It uses a [multicodec](https://github.com/multiformats/multicodec) to indicate its version, making it fully self-describing. |
| 48 | + |
| 49 | +## What is it? |
| 50 | + |
| 51 | +A CID is a self-describing content-addressed identifier. |
| 52 | +It uses cryptographic hashes for content addressing and several |
| 53 | +[multiformats](https://github.com/multiformats/multiformats) for flexible self-description, namely: |
| 54 | + |
| 55 | +1. [multihash](https://github.com/multiformats/multihash) for content-addressed hashing, |
| 56 | +2. [multicodec](https://github.com/multiformats/multicodec) to type that addressed content, and |
| 57 | +3. optionally, [multibase](https://github.com/multiformats/multibase) to encode the binary CID as a string. |
| 58 | + |
| 59 | +The first two form a self-contained binary identifier; the third is added only when the CID is written as text. |
| 60 | + |
| 61 | +Concretely, it's a *typed* content address: a tuple of `(content-type, content-address)`. |
| 62 | + |
| 63 | +## How does it work? |
| 64 | + |
| 65 | +Current version: CIDv1. |
| 66 | + |
| 67 | +CIDv1 is a **binary** format composed of [unsigned varints](https://github.com/multiformats/unsigned-varint) |
| 68 | +prefixing a hash digest to form a self-describing "content address": |
| 69 | + |
| 70 | +```text |
| 71 | +<cidv1> ::= <multicodec-cidv1><multicodec-content-type><multihash-content-address> |
| 72 | +
|
| 73 | +# example: a CIDv1 addressing the raw bytes "hello", in hex |
| 74 | +01 55 12 20 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 |
| 75 | +# 01: cidv1 | 55: raw | 12 20: sha2-256, 32 bytes | 2cf2...: sha2-256 digest of "hello" |
| 76 | +``` |
| 77 | + |
| 78 | +Where |
| 79 | + |
| 80 | +- `<multicodec-cidv1>` is a [multicodec](https://github.com/multiformats/multicodec) representing the version of CID, here for upgradability purposes. |
| 81 | +- `<multicodec-content-type>` is a [multicodec](https://github.com/multiformats/multicodec) code representing the content type or format of the data being addressed. |
| 82 | +- `<multihash-content-address>` is a [multihash](https://github.com/multiformats/multihash) value, which uses a registry of hash function abbreviations to prefix a cryptographic hash of the content being addressed, thus making it self-describing. |
| 83 | + |
| 84 | +## Stringified Form |
| 85 | + |
| 86 | +Since CIDs have many applications outside binary-only contexts, a CID may need to be base-encoded for different consumers or transports. |
| 87 | +In such applications, CIDs are expressed as a Unicode *string* with a [multibase](https://github.com/multiformats/multibase) prefix. |
| 88 | +The multibase prefix identifies the string encoding but is not part of the CID itself; the same binary CID can appear in different bases depending on context and needs such as string length and case-sensitivity. |
| 89 | +The full string form is: |
| 90 | + |
| 91 | +```text |
| 92 | +<cidv1-str> ::= <multibase-prefix><multibase-encoding(<multicodec-cidv1><multicodec-content-type><multihash-content-address>)> |
| 93 | +``` |
| 94 | + |
| 95 | +Where |
| 96 | + |
| 97 | +- `<multibase-prefix>` is a [multibase prefix](https://github.com/multiformats/multibase/blob/master/multibase.csv) (1 Unicode code point) that makes the string self-describing for conversion back to binary. |
| 98 | + |
| 99 | +IPFS implementations SHOULD support at minimum `base58btc` (`z`), `base32` (`b`), `base16` (`f`), and `base36` (`k`, for ed25519 keys in [IPNS Records](https://specs.ipfs.tech/ipns/ipns-record/)). |
| 100 | + |
| 101 | +## Design Considerations |
| 102 | + |
| 103 | +The design of CIDs takes into account many difficult tradeoffs encountered while building [IPFS](https://ipfs.tech). Most of these come from the multiformats project. |
| 104 | + |
| 105 | +- Compactness: CIDs are binary to keep them as compact as possible, since they're meant to be part of longer path identifiers or URIs. |
| 106 | +- Transport friendliness (or "copy-pastability"): CIDs are encoded with multibase to allow choosing the best base for transporting. For example, CIDs can be encoded into base58btc to yield shorter and easily-copy-pastable hashes. |
| 107 | +- Versatility: CIDs are meant to be able to represent values of any format with any cryptographic hash. |
| 108 | +- Avoid Lock-in: CIDs prevent lock-in to old, potentially-outdated decisions. |
| 109 | +- Upgradability: CIDs encode a version to ensure the CID format itself can evolve. |
| 110 | + |
| 111 | +## Versions |
| 112 | + |
| 113 | +### CIDv0 |
| 114 | + |
| 115 | +CIDv0 is a backwards-compatible version, where: |
| 116 | +- the `multibase` of the string representation is always `base58btc` and implicit (prefix `z` not present) |
| 117 | +- the `multicodec` is always `dag-pb` (`0x70`) and implicit (not written) |
| 118 | +- the `cid-version` is always `cidv0` (`0`) and implicit (not written) |
| 119 | +- the `multihash` is written as is but is always a full (length 32) `sha2-256` (`0x12`) hash. |
| 120 | + |
| 121 | +```text |
| 122 | +cidv0 ::= <multihash-content-address> |
| 123 | +``` |
| 124 | + |
| 125 | +### CIDv1 |
| 126 | + |
| 127 | +See the section: [How does it work?](#how-does-it-work) |
| 128 | + |
| 129 | +```text |
| 130 | +<cidv1> ::= <multicodec-cidv1><multicodec-content-type><multihash-content-address> |
| 131 | +``` |
| 132 | + |
| 133 | +## Decoding Algorithm |
| 134 | + |
| 135 | +The binary fields of a CID are [unsigned varints](https://github.com/multiformats/unsigned-varint). |
| 136 | +Two rules hold for every CID: |
| 137 | + |
| 138 | +- each varint MUST be minimally encoded, and a decoder MUST reject any overlong (non-minimal) varint; |
| 139 | +- a decoder MUST reject any bytes left over after the multihash. |
| 140 | + |
| 141 | +A binary CID has one of two shapes, told apart by its leading bytes: |
| 142 | + |
| 143 | +| Leading bytes | Shape | |
| 144 | +| --- | --- | |
| 145 | +| `0x01` | a **CIDv1**, where this first varint is the version field | |
| 146 | +| `0x12 0x20` | a bare 34-byte `sha2-256` multihash: a **CIDv0** | |
| 147 | +| anything else | not a CID; a decoder MUST reject it | |
| 148 | + |
| 149 | +A CIDv0 is identified by the two-byte prefix `0x12 0x20`, not by the leading byte `0x12` alone: `0x12` is the `sha2-256` multihash code and `0x20` is its digest length, 32. A CIDv0 has no version field. |
| 150 | + |
| 151 | +### Decoding a binary CID |
| 152 | + |
| 153 | +To decode a binary CID `bytes`: |
| 154 | + |
| 155 | +1. If `bytes` is exactly 34 bytes long and begins with `0x12 0x20`, it is a **CIDv0**, a bare `sha2-256` multihash (`cidv0 ::= <multihash-content-address>`): |
| 156 | + 1. The 34 bytes are `0x12` (the `sha2-256` code), `0x20` (the digest length, 32), and a 32-byte digest. |
| 157 | + 2. The content type is implicitly `dag-pb` (`0x70`) and is not encoded. |
| 158 | +2. Otherwise, read the leading varint of `bytes`. |
| 159 | +3. If the leading varint is `0x01`, it is a **CIDv1** (`<cidv1> ::= <multicodec-cidv1><multicodec-content-type><multihash-content-address>`): |
| 160 | + 1. The `<multicodec-cidv1>` version field is the `0x01` just read. |
| 161 | + 2. Read the next varint as the `<multicodec-content-type>`, which types the content. |
| 162 | + 3. Read the [`<multihash-content-address>`](https://github.com/multiformats/multihash) that follows, structured as `<hash-code><digest-length><digest>`. |
| 163 | + 4. The `<digest-length>` MUST consume the remaining bytes exactly; a decoder MUST reject a truncated digest or any trailing bytes. |
| 164 | +4. Otherwise, a decoder MUST reject `bytes`. No other leading value is a CID. In particular, reject a leading `0x12` that is not the `0x12 0x20` prefix of a 34-byte input, and reject `0x00`, `0x02` (reserved for the never-deployed CIDv2), and `0x03` (reserved for the never-deployed CIDv3). |
| 165 | + |
| 166 | +### Decoding a CID string |
| 167 | + |
| 168 | +To decode a CID string (ASCII or UTF-8): |
| 169 | + |
| 170 | +1. Convert the string to binary `bytes`: |
| 171 | + - If it is 46 characters long and begins with `Qm`, it is a CIDv0; decode it as `base58btc`. |
| 172 | + - Otherwise, decode it by its [multibase](https://github.com/multiformats/multibase) prefix. |
| 173 | +2. Decode `bytes` as a binary CID (above) and return the result. |
| 174 | + |
| 175 | +# Appendices |
| 176 | + |
| 177 | +:::warning |
| 178 | +These sections provide additional context. This is not part of specification, |
| 179 | +and is provided here only for extra context. |
| 180 | +::: |
| 181 | + |
| 182 | +<!-- TODO: review each implementation for spec conformance before listing here. |
| 183 | + A spec should not reference implementations that may not follow it. |
| 184 | +
|
| 185 | +## Implementations |
| 186 | +
|
| 187 | +- [go-cid](https://github.com/ipfs/go-cid) |
| 188 | +- [java-cid](https://github.com/ipld/java-cid) |
| 189 | +- [js-multiformats](https://github.com/multiformats/js-multiformats) |
| 190 | +- [rust-cid](https://github.com/multiformats/rust-cid) |
| 191 | +- [py-multiformats-cid](https://github.com/pinnaculum/py-multiformats-cid) |
| 192 | +- [elixir-cid](https://github.com/nocursor/ex-cid) |
| 193 | +- [dart_cid](https://github.com/dwyl/dart_cid) |
| 194 | +- [zig_cid](https://github.com/zen-eth/multiformats-zig) |
| 195 | +
|
| 196 | +--> |
| 197 | + |
| 198 | +## FAQ |
| 199 | + |
| 200 | +> **Q. I have questions on multicodec, multibase, multihash, or unsigned-varint.** |
| 201 | +
|
| 202 | +Please check their repositories: [multicodec](https://github.com/multiformats/multicodec), [multibase](https://github.com/multiformats/multibase), [multihash](https://github.com/multiformats/multihash), [unsigned-varint](https://github.com/multiformats/unsigned-varint). |
| 203 | + |
| 204 | +> **Q. Why does CID exist?** |
| 205 | +
|
| 206 | +IPFS originally used base58btc-encoded multihashes, but the need to support multiple data formats via IPLD revealed limitations of bare multihashes as identifiers. |
| 207 | +CIDs were created to provide a self-describing, versioned, typed content address. |
| 208 | +The history of this format is documented at: https://github.com/ipfs/specs/issues/130 |
| 209 | + |
| 210 | +> **Q. Is the use of multicodec similar to file extensions?** |
| 211 | +
|
| 212 | +Yes. Like a file extension, the multicodec in a CID tells consumers how to interpret the bytes. |
| 213 | +And just like file extensions, most users will never change it, but you can swap the codec to change how the same bytes are parsed. |
| 214 | + |
| 215 | +> **Q. What formats (multicodec codes) does CID support?** |
| 216 | +
|
| 217 | +CID can reference content of any type registered in the [multicodec table](https://github.com/multiformats/multicodec/blob/master/table.csv). |
| 218 | +In practice, IPFS primarily uses [`dag-pb`](https://web.archive.org/web/20260305020653/https://ipld.io/specs/codecs/dag-pb/spec/) (`0x70`), [`raw`](https://www.iana.org/assignments/media-types/application/vnd.ipld.raw) (`0x55`), [`dag-cbor`](https://web.archive.org/web/20260305020653/https://ipld.io/specs/codecs/dag-cbor/spec/) (`0x71`), [`dag-json`](https://web.archive.org/web/20260305020653/https://ipld.io/specs/codecs/dag-json/spec/) (`0x0129`), and [`libp2p-key`](https://github.com/libp2p/specs/blob/4e2c796bc77a2639136b277224468b7c48b9fff1/RFC/0001-text-peerid-cid.md) (`0x72`). |
| 219 | + |
| 220 | +> **Q. What is the process for updating CID specification (e.g., adding a new version)?** |
| 221 | +
|
| 222 | +CIDs are a well established standard. |
| 223 | +IPFS uses CIDs for content-addressing and IPNS. |
| 224 | +Changing such a core protocol requires careful review, including feedback from implementers and stakeholders across the ecosystem. |
| 225 | + |
| 226 | +For this reason, changes to the CID specification MUST be submitted as an improvement proposal to [ipfs/specs](https://github.com/ipfs/specs/tree/main/IPIP) repository (PR with [IPIP document](https://github.com/ipfs/specs/blob/main/ipip-template.md)), and follow the IPIP process described there. |
| 227 | + |
| 228 | +## Historical Design Decisions |
| 229 | + |
| 230 | +You can read an [in-depth discussion on why this format was needed in IPFS](https://github.com/ipfs/specs/issues/130) and the [original CIDv1 proposal](https://github.com/multiformats/cid/blob/f638ca68390758f0d4c7f90ac843091d3973cd02/original-rfc.md). |
| 231 | + |
| 232 | +## Human-Readable Form |
| 233 | + |
| 234 | +This is design guidance for tools that present a human-readable CID inspector to a user, such as a debugger, a block explorer, or the diagnostic UI at https://cid.ipfs.tech. |
| 235 | +It is not a wire format: nothing produces or parses it, and it carries no information beyond what the CID already encodes. |
| 236 | + |
| 237 | +When such a UI needs to show what a CID contains, it can expand the already self-describing CID into a labelled listing of its parts: |
| 238 | + |
| 239 | +```text |
| 240 | +<hr-cid> ::= <hr-mbc> "-" <hr-cid-mc> "-" <hr-mc> "-" <hr-mh> |
| 241 | +``` |
| 242 | + |
| 243 | +Where each sub-component is the name of its code in the relevant multiformats registry: |
| 244 | + |
| 245 | +- `<hr-mbc>` is the multibase code name (eg `b` -> `base32`) |
| 246 | +- `<hr-cid-mc>` is the CID version multicodec name (eg `0x01` -> `cidv1`) |
| 247 | +- `<hr-mc>` is the content-type multicodec name (eg `0x55` -> `raw`) |
| 248 | +- `<hr-mh>` is the multihash code name and digest length (eg `sha2-256-256`), then a final dash and the hex digest |
| 249 | + |
| 250 | +For example, the CIDv1 for the raw bytes `hello`: |
| 251 | + |
| 252 | +```text |
| 253 | +# example CID |
| 254 | +bafkreibm6jg3ux5qumhcn2b3flc3tyu6dmlb4xa7u5bf44yegnrjhc4yeq |
| 255 | +# corresponding human readable CID |
| 256 | +base32 - cidv1 - raw - sha2-256-256-2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 |
| 257 | +``` |
| 258 | + |
| 259 | +These names come from the multiformats registries and are provisional labels for human eyes only; only the numeric codes are stable. |
| 260 | +A UI should show the codes next to the names, and no consumer should rely on a name staying the same. |
| 261 | +See: https://cid.ipfs.tech/#bafkreibm6jg3ux5qumhcn2b3flc3tyu6dmlb4xa7u5bf44yegnrjhc4yeq |
0 commit comments