Configuration
Every option accepted by defineConfig, with defaults and types.
On this page
docvia.config.ts at your project root holds the compile settings: renderer,
plugins, components, and Markdown options. Collections are declared in code
with defineDocs(). The Vite plugin loads the config from the
Vite root when called as docvia(), the Next.js wrapper reads it on config
evaluation, and the CLI loads it via loadConfig.
defineConfig
Import defineConfig from your framework plugin: @docvia/build/vite or
@docvia/build/next (@docvia/cli re-exports it too, but the CLI is a
dev-only tool). It takes a Partial<docviaConfig>, fills in defaults, and
returns a fully resolved docviaConfig.
import { defineConfig } from "@docvia/build/vite";
export default defineConfig({
/* ... */
});
Authoring the config through defineConfig is what gives you type-checking and
editor completion on every field.
Top-level options
| Option | Type | Default | Description |
|---|---|---|---|
renderer | RendererAdapter | none | Required. Use createReactRenderer(...) or createSvelteRenderer(...). |
plugins | docviaPlugin[] | [] | Pipeline plugins, sorted by phase then priority. |
components | Record<string, ComponentConfig> or an array of globs and { name, ...ComponentConfig } | none | Components referenced by :::name directives. |
hashExclude | string[] | [] | Frontmatter keys left out of a page's contentHash, for derived or volatile values. |
markdown.remarkPlugins | unknown[] | [] | Extra remark plugins inserted into the parse pipeline. |
theme.name | string | "default" | UI theme name. |
theme.options | Record<string, unknown> | {} | Theme-specific options. |
Syntax highlighting is a plugin. Add
@docvia/plugin-shikitopluginsasshiki({ theme, langs }). It highlights every code block at build time and bakes the HTML into the IR, so no highlighter ships to the browser. It is the recommended default: without a highlighter, docvia warns once that code blocks render unhighlighted. Fence titles, tabs, and npm/pnpm/yarn/bun tabs need no config; see Code blocks.A
syntaxconfig block (syntax.highlighter/syntax.theme/syntax.langs) still exists in the config schema for backward compatibility, but it no longer drives highlighting. Configure theshiki()plugin instead.
Renderers
The renderer field is required; compiling with no renderer throws a
CONFIG_ERROR. Choose the adapter that matches your app:
// React
import { createReactRenderer } from "@docvia/core/react";
renderer: createReactRenderer();
// Svelte: use the /node subpath, the build-time entry
import { createSvelteRenderer } from "@docvia/core/svelte/node";
renderer: createSvelteRenderer();
Syntax highlighting is no longer a renderer option. Add the
shiki() plugin to plugins instead.
Both adapters accept { registry?, transform? }. transform(output, doc)
rewrites the RenderOutput tree of each page before it is serialized:
renderer: createSvelteRenderer({
transform: (output, doc) => output, // return a rewritten tree
});
See @docvia/core/react and
@docvia/core/svelte for the full adapter
API.
Collections
A collection is a folder of Markdown, declared in a source file with
defineDocs() from @docvia/core/source/macro. The bundler plugin rewrites the call
at build time:
import { loader } from "@docvia/core/source";
import { defineDocs } from "@docvia/core/source/macro";
const docs = defineDocs({ dir: "content/docs" });
const api = defineDocs({ dir: "content/api" });
export const source = loader({ baseUrl: "/docs", source: docs.toDocviaSource() });
export const apiSource = loader({ baseUrl: "/api", source: api.toDocviaSource() });
| Option | Description |
|---|---|
dir | Folder relative to the project root, as a string literal. Defaults to "content/docs". May live outside the project root. |
docs.schema | A Standard Schema adding frontmatter fields. See below. |
baseUrl belongs to loader(), not the collection. See
@docvia/core/source for the loader API and meta.json.
Legacy config collections (
collections,sourceDir,outDir, and a top-levelfrontmatterin this file) still work throughvirtual:docvia/source/docvia/source, but new apps should usedefineDocs().
Built-in frontmatter
Every Markdown file may carry a YAML frontmatter block. docvia validates it against this base schema:
| Field | Type | Default | Required |
|---|---|---|---|
title | string | none | yes |
description | string | "" | no |
tags | string[] | [] | no |
draft | boolean | false | no |
order | number | none | no |
slug | string | derived from path | no |
Additional keys you write are preserved and available on page.data. They are
untyped unless you extend the schema.
Extending the frontmatter schema
Pass a Standard Schema (Zod, Valibot, ArkType, ...)
as docs.schema to add typed fields. docvia validates every file against the
base fields plus your schema, and page.data is typed from the schema's output
type. No type files are generated.
import { defineDocs } from "@docvia/core/source/macro";
import { z } from "zod";
const docs = defineDocs({
dir: "content/docs",
docs: {
schema: z.object({
author: z.string(),
publishedAt: z.string().optional(),
}),
},
});
A file that omits a required custom field fails the build with a
SCHEMA_ERROR pointing at the offending file. See
@docvia/core/schema for the validation and codegen details.
Components
Register components once under components, then expose them to your routes
with defineRegistry(), which the bundler plugin rewrites into real imports:
import { defineRegistry } from "@docvia/core/source/macro";
export const registry = defineRegistry();
// Array form: globs and explicit entries. Names come from file names:
// ButtonDemo.svelte becomes button-demo.
components: [
"./src/lib/docs/*.svelte",
{ name: "counter", path: "./src/Counter.svelte", hydrate: true },
];
// Record form
components: {
counter: {
path: "./src/lib/components/Counter.svelte",
hydrate: true,
defaultProps: { initial: 0 },
},
};
Each ComponentConfig has a path, an optional hydrate flag, and optional
defaultProps. Paths resolve from the project root (the config file's
directory), the extension may be omitted, and a missing file fails the compile
with a CONFIG_ERROR. A registered component is referenced from Markdown with
a :::counter directive.
A complete example
import { defineConfig } from "@docvia/build/vite";
import { createSvelteRenderer } from "@docvia/core/svelte/node";
import { shiki } from "@docvia/plugin-shiki";
export default defineConfig({
renderer: createSvelteRenderer(),
components: {
counter: { path: "./src/lib/components/Counter.svelte", hydrate: true },
},
plugins: [
shiki({ theme: "github-dark", langs: ["typescript", "svelte", "bash", "json"] }),
],
});