CINXE.COM
IPLD ♦ Schemas: Links
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="/css/layout.css?1718759055581"> <link rel="stylesheet" href="/css/nav.css?1718759055581"> <link rel="stylesheet" href="/css/style.css?1718759055581"> <link rel="stylesheet" href="/css/prismjs@1.24-themes-prism.css"> <title>IPLD ♦ Schemas: Links</title> </head> <body> <header> <div class="sidebar-button" onclick="document.getElementById('sidebar').classList.toggle('sidebar-open')"> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"> <path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path> </svg> </div> <a href="/" class="logo">IPLD</a> <aside id=breadcrumbs> <ul> <li><a href="/docs">docs</a></li> <li><a href="/docs/schemas">schemas</a></li> <li><a href="/docs/schemas/features">features</a></li> <li><a href="/docs/schemas/features/links/">links</a></li> </ul> </aside> </header> <aside id=sidebar> <nav> <ul> <li> <a href="/docs/">Docs</a><ul> <li> <a href="/docs/intro/">Intro</a><ul> <li> <a href="/docs/intro/hello-world/">Hello, World</a></li> <li> <a href="/docs/intro/primer/">The Brief Primer</a></li> <li> <a href="/docs/intro/ecosystem/">InterPlanetary Ecosystem Overview</a></li> <li> <a href="/docs/intro/community/">Finding Community</a></li></ul></li> <li> <a href="/docs/motivation/">Motivation</a><ul> <li> <a href="/docs/motivation/benefits-of-content-addressing/">Benefits of Content Addressing</a></li> <li> <a href="/docs/motivation/data-to-data-structures/">From Data to Data Structures</a></li></ul></li> <li> <a href="/docs/codecs/">Codecs</a><ul> <li> <a href="/docs/codecs/known/">Known Codecs</a><ul> <li> <a href="/docs/codecs/known/dag-cbor/">DAG-CBOR</a></li> <li> <a href="/docs/codecs/known/dag-json/">DAG-JSON</a></li> <li> <a href="/docs/codecs/known/dag-pb/">DAG-PB</a></li></ul></li></ul></li> <li> <a href="/docs/data-model/">Data Model</a><ul> <li> <a href="/docs/data-model/node/">Nodes</a></li> <li> <a href="/docs/data-model/kinds/">Kinds</a></li> <li> <a href="/docs/data-model/pathing/">Pathing</a></li> <li> <a href="/docs/data-model/traversal/">Traversal</a></li></ul></li> <li> <a href="/docs/advanced-data-layouts/">Advanced Data Layouts</a><ul> <li> <a href="/docs/advanced-data-layouts/intro/">Intro to ADLs</a></li> <li> <a href="/docs/advanced-data-layouts/naming/">ADL Naming</a></li> <li> <a href="/docs/advanced-data-layouts/signalling/">Signalling ADLs</a></li> <li> <a href="/docs/advanced-data-layouts/dynamic-loading/">Dynamic Loading</a></li> <li> <a href="/docs/advanced-data-layouts/known/">Known ADLs</a></li></ul></li> <li> <a href="/docs/schemas/">Schemas</a><ul> <li> <a href="/docs/schemas/intro/">Introduction</a><ul> <li> <a href="/docs/schemas/intro/compare/">compare</a></li> <li> <a href="/docs/schemas/intro/goals/">Goals</a></li> <li> <a href="/docs/schemas/intro/feature-summary/">Feature Summary</a></li></ul></li> <li> <a href="/docs/schemas/features/">Features</a><ul> <li> <a href="/docs/schemas/features/typekinds/">Type Kinds</a></li> <li> <a href="/docs/schemas/features/representation-strategies/">Representation Strategies</a></li> <li class="active-page"> <a href="/docs/schemas/features/links/">Links</a></li> <li> <a href="/docs/schemas/features/indicating-adls/">Using ADLs in Schemas</a></li></ul></li> <li> <a href="/docs/schemas/using/">Using Wisely</a><ul> <li> <a href="/docs/schemas/using/authoring-guide/">Authoring Guide</a></li> <li> <a href="/docs/schemas/using/migrations/">Migrations</a></li></ul></li></ul></li> <li> <a href="/docs/synthesis/">Synthesis</a><ul> <li> <a href="/docs/synthesis/gtd/">Getting Things Done</a></li> <li> <a href="/docs/synthesis/building-in-alignment/">Building in Alignment</a></li> <li> <a href="/docs/synthesis/how-ipfs-web-gateways-work/">How IPFS Web Gateways Work</a></li> <li> <a href="/docs/synthesis/encryption/">Working With Encryption</a></li></ul></li></ul></li> <li> <a href="/specs/">Specs</a><ul> <li> <a href="/specs/about/">About the Specifications</a></li> <li> <a href="/specs/codecs/">Codecs</a><ul> <li> <a href="/specs/codecs/dag-cbor/">DAG-CBOR</a><ul> <li> <a href="/specs/codecs/dag-cbor/fixtures/">DAG-CBOR Test Fixtures</a><ul> <li> <a href="/specs/codecs/dag-cbor/fixtures/cross-codec/">cross-codec</a></li></ul></li> <li> <a href="/specs/codecs/dag-cbor/spec/">Spec</a></li></ul></li> <li> <a href="/specs/codecs/dag-cosmos/">DAG-COSMOS</a><ul> <li> <a href="/specs/codecs/dag-cosmos/basic_types/">basic_types</a></li> <li> <a href="/specs/codecs/dag-cosmos/cosmos_state/">cosmos_state</a></li> <li> <a href="/specs/codecs/dag-cosmos/crypto_types/">crypto_types</a></li> <li> <a href="/specs/codecs/dag-cosmos/tendermint_chain/">tendermint_chain</a></li> <li> <a href="/specs/codecs/dag-cosmos/typed_protobuf/">typed_protobuf</a></li></ul></li> <li> <a href="/specs/codecs/dag-eth/">DAG-ETH</a><ul> <li> <a href="/specs/codecs/dag-eth/basic_types/">basic_types</a></li> <li> <a href="/specs/codecs/dag-eth/chain/">chain</a></li> <li> <a href="/specs/codecs/dag-eth/convenience_types/">convenience_types</a></li> <li> <a href="/specs/codecs/dag-eth/state/">state</a></li></ul></li> <li> <a href="/specs/codecs/dag-jose/">DAG-JOSE</a><ul> <li> <a href="/specs/codecs/dag-jose/fixtures/">fixtures</a></li> <li> <a href="/specs/codecs/dag-jose/spec/">Spec</a></li></ul></li> <li> <a href="/specs/codecs/dag-json/">DAG-JSON</a><ul> <li> <a href="/specs/codecs/dag-json/fixtures/">DAG-JSON Test Fixtures</a><ul> <li> <a href="/specs/codecs/dag-json/fixtures/cross-codec/">cross-codec</a></li></ul></li> <li> <a href="/specs/codecs/dag-json/spec/">Spec</a></li></ul></li> <li> <a href="/specs/codecs/dag-pb/">DAG-PB</a><ul> <li> <a href="/specs/codecs/dag-pb/fixtures/">DAG-PB Test Fixtures</a><ul> <li> <a href="/specs/codecs/dag-pb/fixtures/cross-codec/">cross-codec</a></li></ul></li> <li> <a href="/specs/codecs/dag-pb/spec/">Spec</a></li></ul></li></ul></li> <li> <a href="/specs/advanced-data-layouts/">Advanced Data Layouts</a><ul> <li> <a href="/specs/advanced-data-layouts/fbl/">FBL ADL</a><ul> <li> <a href="/specs/advanced-data-layouts/fbl/spec/">spec</a></li></ul></li> <li> <a href="/specs/advanced-data-layouts/hamt/">HAMT ADL</a><ul> <li> <a href="/specs/advanced-data-layouts/hamt/fixture/">HashMap (HAMT) Test Fixtures</a><ul> <li> <a href="/specs/advanced-data-layouts/hamt/fixture/alice-words/">alice-words</a></li></ul></li> <li> <a href="/specs/advanced-data-layouts/hamt/spec/">spec</a></li></ul></li></ul></li> <li> <a href="/specs/schemas/">Schemas</a><ul> <li> <a href="/specs/schemas/prelude/">prelude</a></li></ul></li> <li> <a href="/specs/transport/">Transports</a><ul> <li> <a href="/specs/transport/car/">CAR</a><ul> <li> <a href="/specs/transport/car/carv1/">CARv1 Specification</a></li> <li> <a href="/specs/transport/car/carv2/">CARv2 Specification</a></li> <li> <a href="/specs/transport/car/fixture/">CAR Test Fixtures</a><ul> <li> <a href="/specs/transport/car/fixture/carv1-basic/">carv1-basic</a></li> <li> <a href="/specs/transport/car/fixture/carv2-basic/">carv2-basic</a></li></ul></li></ul></li> <li> <a href="/specs/transport/graphsync/">Graphsync</a><ul> <li> <a href="/specs/transport/graphsync/known_extensions/">known_extensions</a></li></ul></li> <li> <a href="/specs/transport/trustless-pathing/">Trustless Pathing</a><ul> <li> <a href="/specs/transport/trustless-pathing/fixtures/">Trustless Pathing Fixtures</a><ul> <li> <a href="/specs/transport/trustless-pathing/fixtures/unixfs_20m_variety/">unixfs_20m_variety</a></li></ul></li></ul></li></ul></li> <li> <a href="/specs/selectors/">Selectors</a><ul> <li> <a href="/specs/selectors/fixtures/">fixtures</a><ul> <li> <a href="/specs/selectors/fixtures/selector-fixtures-1/">selector-fixtures-1</a></li> <li> <a href="/specs/selectors/fixtures/selector-fixtures-adl/">selector-fixtures-adl</a></li> <li> <a href="/specs/selectors/fixtures/selector-fixtures-recursion/">selector-fixtures-recursion</a></li></ul></li></ul></li> <li> <a href="/specs/patch/">Patch</a><ul> <li> <a href="/specs/patch/fixtures/">IPLD Patch Test Fixtures</a><ul> <li> <a href="/specs/patch/fixtures/fixtures-1/">fixtures-1</a></li></ul></li></ul></li></ul></li> <li> <a href="/libraries/">Libraries</a><ul> <li> <a href="/libraries/golang/">Golang</a></li> <li> <a href="/libraries/javascript/">JavaScript</a></li> <li> <a href="/libraries/python/">Python</a></li> <li> <a href="/libraries/rust/">Rust</a></li></ul></li> <li> <a href="/design/">Design</a><ul> <li> <a href="/design/objectives/">Objectives</a></li> <li> <a href="/design/concepts/">Concepts</a><ul> <li> <a href="/design/concepts/type-theory-glossary/">type-theory-glossary</a></li></ul></li> <li> <a href="/design/libraries/">Libraries</a><ul> <li> <a href="/design/libraries/nodes-and-kinds/">nodes-and-kinds</a></li></ul></li> <li> <a href="/design/tricky-choices/">Tricky Choices</a><ul> <li> <a href="/design/tricky-choices/dag-pb-forms-impl-and-use/">dag-pb-forms-impl-and-use</a></li> <li> <a href="/design/tricky-choices/map-key-domain/">map-key-domain</a></li> <li> <a href="/design/tricky-choices/numeric-domain/">numeric-domain</a></li> <li> <a href="/design/tricky-choices/ordering/">ordering</a></li> <li> <a href="/design/tricky-choices/string-domain/">string-domain</a></li></ul></li> <li> <a href="/design/open-research/">Open Research</a><ul> <li> <a href="/design/open-research/ADL-autoexecution/">ADL autoexecution</a></li></ul></li></ul></li> <li> <a href="/tools/">Tools</a></li> <li> <a href="/glossary/">Glossary</a></li> <li> <a href="/media/">Media</a></li> <li> <a href="/FAQ/">FAQ</a></li></ul> </nav> </aside> <main> <div class=content> <h1>Links and IPLD Schemas</h1> <p>IPLD Schemas are designed to describe data bounded by blocks. Notably, IPLD Schemas are intentionally <em>not</em> agnostic to block boundaries -- this is necessary to contain the complexity of validation: You ought to be able to apply a schema to a block and have enough information to make fast, complete, validation.</p> <p>The <code>link</code> kind is one of the <a href="../typekinds/">typekinds</a> in schemas. It maps fairly directly to the <a href="/docs/data-model/kinds/#link-kind">data model link kind</a> (in the same way as the <code>int</code> typekind is essentially the same as the data model <code>int</code> kind). However, schema links can also add a bit more information -- as we'll see later, in the <a href="#link-destination-type-hinting">link destination type hinting</a> section.</p> <p>Links define effective block boundaries. E.g.:</p> <pre class="language-ipldsch"><code class="language-ipldsch"><span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Foo</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> baz Int boom Link <span class="token punctuation">}</span></code></pre> <p>Which tells us that there exists a <code>map</code> (the default <code>struct</code> representation) that contains a <code>baz</code> integer property and a <code>boom</code> link property. In this way we can state explicitly where to expect links in the same manner as describing the position of every other data model kind.</p> <p>Links may appear in <code>struct</code>s, as elements of <code>list</code>s and as values of <code>map</code>s. They may also appear in <code>union</code>s if they are also assigned to a type:</p> <pre class="language-ipldsch"><code class="language-ipldsch"><span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">MyKeyedUnion</span></span> <span class="token builtin">union</span> <span class="token punctuation">{</span> <span class="token punctuation">|</span> Foo <span class="token string">"foo"</span> <span class="token punctuation">|</span> Bar <span class="token string">"bar"</span> <span class="token representation">} <span class="token builtin">representation</span></span> keyed <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Foo</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> froz Bool <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Bar</span></span> link</code></pre> <p>This works for and for <code>envelope</code> <code>union</code>s, and also <code>kinded</code> <code>union</code>s, as <code>link</code> is a kind that can be discriminated. <code>inline</code> <code>union</code>s, however, currently describe complex types (structs) so cannot directly describe <code>link</code>s, although the containing <code>struct</code>s may contain <code>link</code>s.</p> <h2 id="link-destination-type-hinting" tabindex="-1"><a class="header-anchor" href="#link-destination-type-hinting">Link Destination Type Hinting</a></h2> <p>In many cases it is helpful to describe what is intended to occur across block boundaries, even though this cannot be verified by schemas in their per-block usage. For the purpose of codegen and as a documentation tool, we can provide "hinting" regarding the shape of the data (in schema terms) on the other side of a link.</p> <p>We use the <strong><code>&</code></strong> operator to convert a complex <code>type</code> into a link, where, for the purpose of in-block validation we expect the thing it describes to be a <code>link</code>, but for the purpose of cross-block traversal we can <em>suggest</em> that what is on the other side of the <code>link</code> is of a particular <code>type</code>.</p> <p>In our original <code>struct</code> example, we could suggest that the <code>boom</code> property of <code>Foo</code>, when followed, will yield a <code>Grop</code>:</p> <pre class="language-ipldsch"><code class="language-ipldsch"><span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Foo</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> baz Int boom <span class="token punctuation">&</span>Grop <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Grop</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> description String x Float y Float data <span class="token punctuation">[</span> Int <span class="token punctuation">]</span> <span class="token punctuation">}</span></code></pre> <p>For the purpose of validation this works for <code>Foo</code> in precisely the same way as our original example; we still expect <code>boom</code> to be a link, and such validation may be successful regardless of what might be found if the link were followed. But we are now providing a "hint" that we expect that when following the link at <code>boom</code> we should find an object that can be described by <code>Grop</code>.</p> <p>In the same way, our <code>keyed</code> <code>union</code> may be made more sophisticated to describe what we expect to be found if we were to follow the link:</p> <pre class="language-ipldsch"><code class="language-ipldsch"><span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">MyKeyedUnion</span></span> <span class="token builtin">union</span> <span class="token punctuation">{</span> <span class="token punctuation">|</span> Foo <span class="token string">"foo"</span> <span class="token punctuation">|</span> <span class="token punctuation">&</span>Grop <span class="token string">"bar"</span> <span class="token representation">} <span class="token builtin">representation</span></span> keyed <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Foo</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> froz Bool <span class="token punctuation">}</span></code></pre> <p>There is no facility in IPLD Schemas for implicitly describing a "may be a link, or may be inline" data structure. However we can do this explicitly with <code>kinded</code> <code>union</code>s, although without strong guarantees regarding what we might find when we follow a link:</p> <pre class="language-ipldsch"><code class="language-ipldsch"><span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">HashMapNode</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> map Bytes data <span class="token punctuation">[</span> Element <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">Element</span></span> <span class="token builtin">union</span> <span class="token punctuation">{</span> <span class="token punctuation">|</span> HashMapNode map <span class="token punctuation">|</span> <span class="token punctuation">&</span>HashMapNode link <span class="token punctuation">|</span> Bucket list <span class="token representation">} <span class="token builtin">representation</span></span> kinded <span class="token comment"># ... further definitions for `Bucket`</span></code></pre> <p>In this example, from the <a href="https://github.com/ipld/specs/blob/master/data-structures/hashmap.md">HashMap</a> specification, we describe a <code>map</code>, named <code>HashMapNode</code> that contains a <code>data</code> property which is a list of <code>Element</code>s. These <code>Element</code>s may be one of three things: a <code>map</code> that contains another <code>HashMapNode</code> (an inlined child for a tree data structure), a <code>link</code> which is assumed to lead to a <code>HashMapNode</code> (a linked child) or a <code>Bucket</code> (not described here) which comprises a <code>list</code>.</p> <p>Our validator can scan the <code>data</code> list and check that each element is one of: <code>map</code>, <code>link</code> and <code>list</code>. We make no strong assertions that the <code>link</code> actually yields a <code>HashMapNode</code> but such assertions may be built into code generated from this schema <em>when</em> the link is loaded and validated.</p> </div> </main> </body> </html>