Configuration›Configuration reference

Configuration reference

Every field a site accepts in refrakt.config.json, grouped by what it does.

This page is generated from refrakt.config.schema.json — the same schema your editor validates against — so it lists what the code actually accepts rather than what someone remembered to write down. For how the file is shaped (single-site, multi-site, path resolution), see Sites.

note

Fields marked theme-defaultable can also be supplied by a theme's manifest. The site config wins; the theme is the fallback.

Content and theme

What the site is built from.

contentDir

string · required

Path to the content directory, relative to the project root. Required for a site to load.

theme

string | SiteThemeConfig · required

Active theme — accepts a package name string (legacy shorthand) or a full SiteThemeConfig with presets, token overrides, mode overlays, and code-block colour scheme.

target

string

Documentation-only adapter hint (svelte, astro, next, nuxt, eleventy, html). No adapter validates or reads this field today; it serves as an in-config record of the intended adapter. Slated for removal in v1.0.

Site identity

Used for canonical links, social cards and structured data. Every field here is theme-defaultable.

baseUrl

string

Public base URL of the site, used for canonical links, `og:url` and `og:image`.

siteName

string

Human-readable site name, used for `og:site_name` and Organization JSON-LD.

string

Site logo path used in Organization JSON-LD (e.g. `/favicon-192.png`).

defaultImage

string

Default `og:image` for pages that do not set their own. 1200×630 is recommended.

Routing and entities

How pages map to layouts, and which of them become registry entities.

routeRules

RouteRule[]

Route-to-layout mapping rules, evaluated in order — first match wins. A rule may also set `entity`, registering matching pages as registry entities of that type (e.g. `runes/**` → `rune`) without per-page frontmatter.

entityRoutes

EntityRoute[]

Declarative entity → page routes. Each rule generates one page per registered entity matching `type` plus an optional `filter` — the built-in alternative to writing a `contributePages` pipeline hook by hand.

Runes and plugins

Which runes exist, and which package wins when names collide. See Plugins for the conflict-resolution knobs in full.

plugins

string[]

Plugins to merge into this site's ThemeConfig (runes, layouts, hooks, etc.).

runes

RunesConfig

Rune resolution — which package wins when several define the same rune name, extra tag names for existing runes, runes loaded from local files, and the project's own composed rune definitions.

overrides

Record<string, string>

Component overrides, mapping a `typeof` name to a component path relative to the project root.

Presentation

Cross-cutting visual configuration.

icons

Record<string, string>

Custom icon SVGs, merged into the theme's global icon group and referenced by name.

tints

Record<string, object>

Project-level tint presets, available to any page or rune via the `tint` attribute.

backgrounds

Record<string, object>

Named bg presets (keyed by name). Each is a BgPresetDefinition: `style` and/or token-driven `gradient` (engine-resolved), `extends` a base preset, and/or `sandbox` ({ src, framework?, dependencies? }) for a live sandbox backdrop resolved at transform time (SPEC-104). `sandbox` presets are project-level content.

highlight

HighlightConfig

Legacy syntax-highlighting configuration — picks a Shiki built-in theme by name (or a `{ light, dark }` pair) for fenced code blocks. The recommended modern approach is `theme.presets` (which contribute `--rf-syntax-*` token overrides via Lumina syntax presets like `@refrakt-md/lumina/presets/nord`) plus `theme.code.colorScheme` for forced light/dark code blocks. Kept for back-compat; both mechanisms can coexist.

sandbox

SandboxConfig

Sandbox configuration — the runtime program-source directory scanned at build time (SPEC-104, ADR-022).

boolean

Whether to render the site-wide search UI (header button + Cmd/Ctrl+K dialog, powered by Pagefind). Defaults to true. Set false to omit the search chrome entirely. Results require a Pagefind index built and served at /pagefind/ — see the Setting up search guide.

Content sources

Where source links resolve from.

repoUrl

string

Canonical GitHub (or compatible) repository URL — e.g. `https://github.com/owner/repo`. Used by the `file-ref` rune (SPEC-078) to build deep-link `View source on GitHub →` URLs of the form `{repoUrl}/blob/{repoBranch}/{path}#L{start}-L{end}`. When absent, `file-ref` falls back to a no-href link / in-page anchor with a build warning.

repoBranch

string

Git ref appended to GitHub source URLs — accepts any branch name, tag, or commit SHA. Defaults to `main` when omitted. Use a commit SHA for archival URLs that won't drift when the file is edited later.

Internationalisation

Locale selection and string overrides — see i18n for the resolution order.

locale

string

Active locale (BCP 47, e.g. `de`). Selects first-party and plugin translation bundles for framework-generated UI text and drives locale-aware date/number formatting. Defaults to `en`.

strings

Record<string, string | Record<string, string>>

Site-level translation overrides for framework-generated UI text, keyed by the auto-derived i18n key (`{scope}.{block}.{ref}`). Highest precedence — these win over first-party and plugin bundles. Each value is a string, or a map of CLDR plural categories (`one`, `other`, …) to strings.

Content validation

Which authoring mistakes the build reports, and how to narrow that.

Seven ids are enabled out of the box:

idwhat it catches
tag-undefinedA rune name that does not exist — a typo, or a rune you removed. Without this the tag is dropped and its children render as bare prose, so the block silently vanishes.
attribute-undefinedAn attribute the rune does not declare. Dropped silently.
attribute-value-invalidA value outside the attribute's matches enum. Passed through as written, usually landing on a data-* attribute no CSS matches.
attribute-missing-requiredA required attribute you did not supply.
attribute-type-invalidA value of the wrong type — most often a quoted boolean or number, which is truthy and so appears to work.
registers-source-unresolvedA rune's registers block reads a source the rune never provides, so every use of it registers an empty id or field. Reported at warning severity, on the line of the rune that triggered it. Only fires for runes that declare registers.
content-unmatchedContent inside a rune that no field of its content model matches — a block written before the first section of a rune whose preamble does not take it, or a --- zone the rune does not read. The rune would drop it from the page. Reported at error severity on the rune's line, naming the dropped node and its own line, so refrakt validate exits non-zero. Fix it in the rune's content model: add a field that takes the content, or set rawBody on a rune that reads its body as raw source.
slot-header-roleA composed rune places a slot's content where a section reads a header role the slot is not named for, for example a description slot read as the blurb. Reported at warning severity, on the composed rune's line, naming the rune, the slot, the role and both remedies: name the field for the role, or set header on the section. The page renders the same either way.

Everything else Markdoc can report is off. variable-undefined in particular is not something to switch on: Markdoc validates the full variable path and has no scope model, so every $item inside a {% collection %} template and every $row inside a {% data %} per-row template is reported as undefined.

Findings become pipeline warnings. Nothing is written into the page.

validation

ValidationConfig

Content validation (SPEC-132). Every rune schema declares required attributes, typed attributes and `matches` enums; the build checks them with `Markdoc.validate()` and reports findings as pipeline warnings. Nothing is rendered into the page. Findings whose level is `critical` — a parse error, an unclosed tag, a tag in an impossible position — are reported whatever you set here: they mean the document could not be understood, which is not a matter of preference. Suppression is deliberately per-site and per-error-id only. There is no per-page or per-tag switch, because that granularity silences the one call site that revealed a real bug. Three options: `enabled` (false turns the pass off for this site), `ids` (replace the default error-id list entirely) and `disableIds` (stop treating specific ids as problems — they are demoted to `info`, not dropped). The defaults are `tag-undefined`, `attribute-undefined`, `attribute-value-invalid`, `attribute-missing-required` and `attribute-type-invalid`.

note

critical findings — a parse error, an unclosed tag, a tag in a position its schema forbids — are reported whatever you configure. They mean the document could not be understood, which is not a matter of preference.

Suppression is per-site and per-error-id only, on purpose. There is no per-page or per-tag switch: that granularity is how you end up silencing the one call site that revealed a real bug.

Top-level

Fields that sit outside a site entry, at the root of the file. Everything else above belongs inside site (or an entry under sites).

plan

PlanConfig

Plan-management configuration.

stale

StaleConfig

Which edges `refrakt stale` must not measure. Two lists rather than one generic `exclude`, because they name opposite sides of an edge and opposite reasons: a single ignore list is the easy way to make the report disappear one page at a time. A page that is merely noisy belongs in neither — fix the extraction rule, or narrow the page's subject with `documents:` in its frontmatter. Both lists default to empty.

xrefs

XrefPattern[]

Cross-reference URL templates. Patterns are tried in array order when an xref's ID isn't found in the registry (or when the registry-found entity has no usable `sourceUrl`). First match wins.

fileRoots

Record<string, string>

Named file roots — directories that file-reading runes can reach via a `namespace:filename` syntax (e.g. `{% partial file="shared:footer.md" /%}`). Keys are namespace names; values are paths relative to the project root and must point at existing directories. The namespace `site` is reserved.

Keeping this page honest

The rows above come from site/content/_data/config-fields.json, generated by scripts/generate-config-reference.mjs from the schema. A colocated test fails when the artifact is stale, when a schema field has no group, or when a group entry names a field that no longer exists — so a field added to the config cannot quietly go undocumented.

Regenerate with:

npm run config:reference

See also

  • Sites — single-site vs multi-site, and path resolution
  • Plugins — installing plugins and resolving rune conflicts
  • Schema — using the published JSON Schema in your editor