inmake DOCS
Docs / Server / Repository modes & references

Repository modes & references

local / remote / preferLocal / preferRemote, and how reference fields resolve.

Repository modes#

mode behaviour
local cache only; miss → undefined
remote always core; write-through into cache
preferLocal (default) cache hit wins; miss → core (then cache)
preferRemote core first; on network/error → cache fallback

list() can't be answered from a per-id cache: every mode except local (which returns []) queries core and writes each result through.

Reference fields#

Data documents don't embed referenced content — a schema kind:'reference' field stores a pointer (DocReference / DocListReference / CollectionReference / SiblingReference). resolveReferences(entity, repo, {locale}) deep-walks an entity and replaces each pointer with the fetched content: document → the doc, list → the docs in stored order, collection → the live query result, sibling → the ONE doc immediately before/after the carrying doc in the value's order_by ({type:'sibling', direction:'prev'|'next'}; the carrying doc's identity comes from ResolveReferencesOptions.self, reset per fetched doc — no self, a collection mismatch, or the sequence's edge resolve to undefined; prev needs an order_by, reversed manual order has no backend form). A CollectionReference without an explicit order_by follows the collection's manual admin order when one is set (setup/data reorder + order — applied server-side by the core /public/content listing). A CollectionReference whose query filters one field and whose order_by (or a range) names another runs on a query key of the collection — keys live on the collection, never on the page. Most listings need nothing: the common shapes are built in (status + newest, status + a date field, the first enum field + date / newest; products by status + price / name / newest, and the category / tag pages on platform composites). Only a shape beyond them needs a declared key on the setup/data row (keys: {name: [fields]}); without it the core sorts up to 500 matching documents in memory and above that answers 400 query_key_required {collection, suggest} — declare suggest as the key (drop-core-sdk README, "Query keys"). It also returns the dependencies of the resolution (deps.keys — resolved doc cache keys; deps.collections — locale/collection of collection AND sibling references, since any write in the collection can change who the sibling is), which WebSite uses to drop rendered pages when a hook push arrives for a referenced doc or for any doc in a queried collection.

A document (or sibling) reference whose value carries render:true is rendered through the target's OWN schema template (renderDoc, supplied by WebSite) and the fragment lands on the resolved value as html. Such a target is resolved like a root first, whatever depth the walk has left (renderDepth): its element placements render and its own references resolve one hop, so a component that is just {{{ cta.html }}} over a library element embeds at the default depth 1 — before this, renderDoc received the raw placement pointer and the component rendered empty. The hop is cycle-guarded (a component embedding itself renders once, then falls back to data), and renderDoc also receives the doc as fetched (stored) as the parallel twin for datetime localization and edit-mode provenance.

The resolver also descends into blocks TextValue envelopes (kind:'editor' content): each element block's ElementReference resolves through the same renderElement path as a standalone placement — the rendered markup lands on the block as html (what flatten's blocksToHtml emits in place), its CSS/JS hoist as fragments, and its library doc registers as a dependency, so editing a placed element re-renders the pages that carry it.

Link fields (kind:'link') resolve too, but to a URL rather than to content. A link value is either a plain string used verbatim (#kontakt, tel:…, https://…) or a LinkReference envelope {type:'link', collection, document?, hash?}; the resolver replaces the envelope with a LinkUrlValue — a String hybrid whose primitive is the target's public URL in the serve locale (href="{{cta.href}}") and whose .title is the target's title ({{cta.href.title}}), toJSON() giving the plain URL for DROP_DATA. The URL comes from core-lib's linkPathOf: the homepage doc → /, else the target's seo.slug under its seo.scope and the collection route (/{segment}/{slug} when routed, the flat /{slug} otherwise), else /ref/{collection}/{document}; a missing target resolves to undefined (guard with {{#if}} — a hidden button beats a dead link), a document-less link points at a routed collection's own /{segment}. Pass ResolveReferencesOptions.site ({dataSetup, index} — setup/data + setup/web.index) so routes and the homepage rule apply; without it links fall back to flat slugs. The named target joins deps.keys exactly like a document reference, so a slug rename evicts the linking page; the target is never walked or rendered. WebSite applies the same derivation to setup/web.shell.menu items whose page is a document pointer (a tagged link or the legacy {collection, document}; a missing label takes the target's localized title; the targets join the shell deps), and stringifyLinks(entity, repo, {locale, site}) — the same rule producing plain URL strings, everything else untouched — runs on the documents the load-more and variant routes hand to the browser.