Store layout (key–value mapping)
A store is any key–value namespace with string keys and byte-string values,
supporting at least get and set (an absent key reads as absent, and a
null/absent distinction at the driver level MUST both mean absent).
Optional capabilities (has, key enumeration by prefix, delete) enable
existence checks and garbage collection but are not required for
conformance.
Three key spaces share the namespace:
key value
─────────────────────────────────────────────── ─────────────────────────
meta:format (store metadata, §10.3) canonical CBOR map
blocks:ciqk2p…q4 (base32 of the multihash) raw block bytes
blocks:ciqfx3…zb canonical CBOR node bytes
refs:heads:main (hierarchy spelled ':') binary CIDv1 (§4)
refs:heads:release binary CIDv1
refs:backup-2026-01-01 <empty> = tombstone#10.1 Blocks
blocks:<base32(multihash)> → the block bytes. The key is the unpadded
lowercase base32 (§3.2) of the ref's binary multihash — hash-function
code, digest length, digest (§4) — and of nothing else: the codec is
excluded, because block identity is the multihash alone (§4). Under
SHA2-256 every block key therefore starts blocks:ciq (the base32 of the
0x12 0x20 multihash prefix). This is the same keying decision mainstream
IPLD block stores converged on (storage keyed by the raw multihash,
codec-agnostic): a unfs store and an IPLD blockstore agree on what a block
is, and blocks referenced under both codecs are stored once.
The block namespace is append-only in normal operation; only garbage collection (§15.2) ever deletes.
#10.2 Named refs
refs:<name> → the ref's binary CIDv1 (§4), bare (no multibase
prefix). Readers MUST validate the value under the full rules of §4 —
CIDv1, codec raw or dag-cbor, the store's multihash — before use; a value
that fails (including a well-formed CID with an unsupported codec) is an
undecodable ref value and, during garbage collection, aborts the sweep
fail-closed (§15.2).
Name rules. A ref name MUST be 1–512 UTF-8 bytes and MUST NOT contain
NUL, /, \, or ?, and MUST NOT have a leading, trailing, or repeated
:. Names MAY be hierarchical, spelled with : (e.g. heads:main).
Rationale (binding): the accepted names are exactly the fixed points of
key normalization — common storage layers map / and \ to :, collapse
: runs, and strip leading/trailing :. Allowing a non-fixed-point name
would let two distinct names alias onto one underlying key — the second
binding silently destroys the first, and any liveness analysis rooted at
names then treats the loser's entire tree as garbage. : itself is safe
because it is the target of that mapping, never a source. Block keys
need no such rule: lowercase base32 contains no separator characters.
Tombstones. Deleting a name on a store without a delete capability is
performed by writing an empty value. Readers MUST treat an empty value
as "name absent", on every store — including stores that do have delete: a
tombstone already written is never reinterpreted as data. A tombstone is
not a reservation, though: a later set of a non-empty ref value rebinds
the name normally, exactly as if the key had never existed.
#10.3 Store metadata
meta:format → a canonical-CBOR map (§5) that makes the store
self-describing:
v— integer, MUST be1for this version (§15.1).hash— text, a hash function identifier (§10.4): the multicodec registry name of a multihash function. MUST name the store's hash function (§3.4), and MUST agree with the multihash code carried by every ref in the store (§4).params— map, OPTIONAL: the writer parameters in effect (§14), with integer fieldsinlineThreshold,pageThreshold,maxChunkRefs,chunkMin,chunkAvg,chunkMaxand a text fieldchunker, each OPTIONAL; an absent field means "the default". The §14 constraints MUST hold over the effective values (each absent field taking its default); a set that violates them is an error, exactly as an unknown field is. ThechunkMin/chunkAvg/chunkMaxtriple is the bounds of thefastcdcchunker (§9.4).
Writers MUST write meta:format when initializing a store, before the
first block or ref. Readers MUST consult it before interpreting any block
or ref: an absent key, an unknown map field, an unrecognized v, or an
unsupported hash is an error. (An unrecognized v here is the
future-version signal, distinct from corruption — see §15.1.)
The metadata value is not content-addressed and is never hashed; rewriting
it is an administrative act. Changing hash on a non-empty store is never
valid (§3.4: one store = one hash).
Reserved keys. Every key outside the three key spaces above —
including all of meta: beyond meta:format — is reserved for future
versions of this specification. Writers MUST NOT create reserved keys;
readers MUST ignore them.
#10.4 Hash function identifiers
A hash function identifier is the multicodec registry name of a multihash function (§2.5) — the registry, not this specification, mints identifiers. The store metadata records the name; every ref carries the corresponding code (§4); the two MUST agree.
| identifier | registry code | hash function | output length |
|---|---|---|---|
"sha2-256" | 0x12 | SHA2-256 | 32 |
sha2-256 is the default and the only function this version requires
implementations to support. A deployment MAY use any other registered
multihash function whose output length satisfies §3.4 ([20, 64] bytes;
never the identity function, code 0x00), naming it by its registry
name here and by its registry code in refs; two deployments interoperate
at the store level only when they support the same function. An
unregistered function has no name or code to carry and cannot be used.