A Markdown documentation compiler. docvia turns a directory of Markdown into typed, pre-rendered content for React, Svelte, or any framework with a renderer adapter — and it runs in three modes from one shared compile core:
- Build — compile the whole tree ahead of time into a typed module graph.
- Dev — compile in-process inside the framework dev server, recompiling incrementally on every file change.
- SSR — render a single document per request, on Node or the edge.
All three sit on the same long-lived CompileService (@docvia/runtime), so
output is byte-identical regardless of mode. See MODES.md for the
full breakdown.
- IR-based. Markdown is parsed, sanitized, and transformed into an Intermediate Representation once; renderers turn that IR into framework output.
- Typed frontmatter. Extend the built-in schema with a Zod object and docvia
generates a
Frontmatterinterface for every collection. - Incremental. A content-addressed cache skips unchanged files — across builds and, in dev, on every keystroke.
- Pluggable. Five hook points across the pipeline, plus build-time syntax highlighting that bakes HTML into the IR so no highlighter ships to the browser.
- Framework adapters. First-party React and Svelte renderers, an in-process Vite plugin, and a Next.js wrapper (webpack + Turbopack).
pnpm add -D @docvia/cli
pnpm add @docvia/renderer-react # or @docvia/renderer-sveltenpx docvia init # scaffold docs/ + docvia.config.ts
npx docvia build # compile to .docvia/
npx docvia dev # watch & recompile incrementallyMinimal docvia.config.ts:
import { defineConfig } from "@docvia/cli";
import { createReactRenderer } from "@docvia/renderer-react";
import { shiki } from "@docvia/plugin-shiki";
export default defineConfig({
sourceDir: "docs",
outDir: ".docvia",
renderer: createReactRenderer(),
plugins: [shiki({ theme: "github-dark" })],
});After docvia build, import the generated source:
// Vite resolves a virtual module; Next.js aliases the bare specifier.
import { docs } from "virtual:docvia/source"; // Next.js: "docvia/source"
const page = await docs.getPage(["getting-started"]); // slug segments
const all = docs.getPages(); // metadata for every page
const tree = docs.pageTree; // navigation treeThe recommended setup runs docvia in-process inside your bundler — no
separate docvia build step, incremental recompilation in dev, and a virtual
source module (virtual:docvia/source on Vite, the aliased docvia/source on
Next.js) so nothing is written to disk during development.
pnpm add -D @docvia/plugin-vite @docvia/cli
pnpm add @docvia/renderer-svelte @docvia/source// vite.config.ts
import { docvia } from "@docvia/plugin-vite";
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import docviaConfig from "./docvia.config";
export default defineConfig({
plugins: [sveltekit(), docvia(docviaConfig)],
});docvia() runs the CompileService in-process: it serves virtual:docvia/source
(and virtual:docvia/source/browser) as virtual modules in dev with incremental
HMR, and serves them from the load hook for production builds too. The config must use the Svelte renderer
(createSvelteRenderer from @docvia/renderer-svelte/node). Consume pages in a
catch-all route via docs.getPage(...) and render them with the Renderer
component from @docvia/renderer-svelte. See
examples/demo-svelte and apps/docs
for working setups.
pnpm add -D @docvia/plugin-next @docvia/cli
pnpm add @docvia/renderer-react @docvia/source react react-dom// next.config.mjs
import { withDocvia } from "@docvia/plugin-next";
export default withDocvia({ configPath: "./docvia.config.ts" })({
reactStrictMode: true,
});withDocvia drives the CompileService when the Next config is evaluated,
aliases docvia/source for both webpack and Turbopack, and runs an
incremental watcher in dev. See examples/demo-next.
Markdown is loaded in place as a module via the ?docvia loader (Vite,
webpack, and Turbopack), so a framework app renders pages directly through its
renderer — including on the edge — with no separate content store. One module
imports the pages eagerly (server/SSR, bundled), another lazily (client,
code-split per page):
// Server / SSR (eager). Vite resolves a virtual module; Next.js aliases the
// bare specifier:
import { docs } from "virtual:docvia/source"; // Next.js: "docvia/source"
// Browser (lazy, code-split per page) — aliased so it doesn't clash with the
// eager import above:
import { docs as browserDocs } from "virtual:docvia/source/browser"; // Next.js: "docvia/source/browser"
const page = await docs.getPage(["getting-started"]);
const lazyPage = await browserDocs.getPage(["getting-started"]);For a non-framework Node server that renders per request, @docvia/ssr
renders IR resolved by a content source — a live CompileService already is
one, so pass it directly:
import { createDocviaSSR } from "@docvia/ssr";
const ssr = createDocviaSSR({ provider: service }); // or a (collection, slug) => IR fn
const page = await ssr.render("docs", "getting-started");Rendered pages are cached in an in-memory LRU keyed by content hash.
docvia preview serves .docvia/ over sirv — a sanity check for the compiled
output only. It is not a runtime; use a framework integration for a real site.
| Package | Version | Purpose |
|---|---|---|
@docvia/cli |
init / build / dev / preview commands. |
|
@docvia/runtime |
CompileService — the stateful compile core shared by build, dev, and SSR. |
|
@docvia/compiler |
Batch build entry (compile()), a thin wrapper over CompileService. |
|
@docvia/core |
Markdown parsing pipeline (unified + remark + rehype). |
|
@docvia/ir |
Intermediate representation, error system, AST → IR transform. | |
@docvia/schema |
Frontmatter validation (Zod), YAML extraction, TS codegen. | |
@docvia/plugins |
defineConfig, loadConfig, PluginRunner. |
|
@docvia/ssr |
Request-time rendering for non-framework Node servers. | |
@docvia/renderer-core |
Framework-agnostic rendering engine and default renderers. | |
@docvia/renderer-react |
React renderer adapter (server + ./client hydration). |
|
@docvia/renderer-svelte |
Svelte renderer adapter. | |
@docvia/search |
Section-level Orama indexing and client search helper. | |
@docvia/source |
Runtime collection model (createCollection / createSource) for the generated source module. |
|
@docvia/plugin-vite |
In-process Vite plugin (docvia()) with virtual modules + HMR. |
|
@docvia/plugin-next |
Next.js wrapper (withDocvia) — webpack + Turbopack. |
|
@docvia/plugin-shiki |
Build-time syntax highlighting via Shiki (pluggable). | |
@docvia/plugin-openapi |
Generate reference pages from an OpenAPI spec. |
v0.2 preview. APIs are stabilizing; expect breaking changes before v1.0. See
.changeset/ for in-flight release notes and
documentation.md for architecture notes.
Contributions are welcome. See CONTRIBUTING.md for the local setup, watch modes, and release workflow.
MIT