Framework integration
Wire docvia into SvelteKit, Next.js, a plain Vite app, or a server — with in-process compilation and a production build.
The recommended way to use docvia is to run it in-process inside your
bundler. The Vite plugin and the Next.js wrapper both drive the compile core
directly — so there is no separate docvia build step, dev recompiles
incrementally as you edit, and the compiled source module is resolved for you
(virtual:docvia/source on Vite, docvia/source on Next.js).
The pattern is the same everywhere:
- Author a
docvia.config.tswith the renderer that matches your framework. - Add the framework's docvia plugin / wrapper.
- Import compiled pages from the source module and render them with the framework renderer.
This page covers SvelteKit, Next.js, plain Vite, and server-side rendering.
SvelteKit
SvelteKit runs on Vite, so the integration is the single docvia() plugin
from @docvia/plugin-vite.
1. Install
pnpm add -D @docvia/plugin-vite @docvia/cli
pnpm add @docvia/renderer-svelte @docvia/source
2. Configure docvia
Use the Svelte renderer — note the /node subpath, which is the build-time
entry point. Add @docvia/plugin-shiki for syntax highlighting.
// docvia.config.ts
import { defineConfig } from "@docvia/cli";
import { createSvelteRenderer } from "@docvia/renderer-svelte/node";
import { shiki } from "@docvia/plugin-shiki";
export default defineConfig({
sourceDir: "src/docs",
outDir: ".docvia",
collections: [{ name: "docs", sourceDir: "src/docs", baseUrl: "/docs" }],
renderer: createSvelteRenderer(),
plugins: [shiki({ theme: "github-dark" })],
});
3. Add the Vite plugin
docvia() runs the CompileService in-process. Following the Vite
virtual-module convention it serves virtual:docvia/source (and
virtual:docvia/source/browser) from its load hook — in dev with incremental
recompilation (HMR), and for production builds alike.
// 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)],
});
That is the whole setup. Your workflow is just pnpm dev and pnpm build —
docvia() compiles your Markdown as part of each.
4. Declare the module types
docvia writes a docvia-env.d.ts at the project root for you so the virtual
modules resolve in TypeScript. It looks like this:
declare module "virtual:docvia/source" {
const source: typeof import("./.docvia/source");
export const docviaSource: typeof source.docviaSource;
export const docs: typeof source.docs;
export const registry: typeof source.registry;
}
declare module "virtual:docvia/source/browser" {
const browser: typeof import("./.docvia/browser");
export const docs: typeof browser.docs;
}
5. Consume pages in a route
A catch-all route loads the page on the server and renders it with the
Renderer component from @docvia/renderer-svelte.
// src/routes/docs/[...slug]/+page.server.ts
import { error } from "@sveltejs/kit";
import { docs } from "virtual:docvia/source";
import type { PageServerLoad } from "./$types";
export const load: PageServerLoad = async ({ params }) => {
const page = await docs.getPage(params.slug ? params.slug.split("/") : []);
if (!page) throw error(404, "Page not found");
return { page };
};
<!-- src/routes/docs/[...slug]/+page.svelte -->
<script lang="ts">
import { Renderer } from "@docvia/renderer-svelte";
import { registry } from "virtual:docvia/source";
import type { PageProps } from "./$types";
let { data }: PageProps = $props();
</script>
<article>
<Renderer nodes={data.page.content} {registry} />
</article>
Build the sidebar from docs.pageTree and you have a fully docvia-driven docs
section. The apps/docs
app in this repository is a complete working example — it dogfoods docvia for
its own documentation.
Next.js
For Next.js, @docvia/plugin-next does the wiring. It
drives the compile core when the Next config is evaluated and aliases
docvia/source for both webpack and Turbopack.
1. Install
pnpm add -D @docvia/plugin-next @docvia/cli
pnpm add @docvia/renderer-react @docvia/source react react-dom
2. Configure docvia
// 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" })],
});
3. Wrap the Next config
// next.config.mjs
import { withDocvia } from "@docvia/plugin-next";
export default withDocvia({ configPath: "./docvia.config.ts" })({
reactStrictMode: true,
});
withDocvia runs CompileService on config evaluation, aliases
docvia/source and docvia/registry for webpack and Turbopack alike, and in
dev starts an incremental watcher that recompiles changed files through
service.invalidate(). A cross-process lock (.docvia-build.lock) keeps
concurrent Next.js workers from compiling at once.
4. Consume pages in a route
// app/docs/[[...slug]]/page.tsx
import { docviaSource } from "docvia/source";
import { DocviaContent } from "@docvia/renderer-react";
export function generateStaticParams() {
return docviaSource.collections.docs.generateParams("slug");
}
export default async function DocPage({
params,
}: {
params: { slug?: string[] };
}) {
const page = await docviaSource.collections.docs.getPage(params.slug);
if (!page) return null;
return <DocviaContent nodes={page.content} />;
}
DocviaContent carries no "use client" directive, so it renders as a React
Server Component. For interactive component islands, hydrate them on the client
with hydrate from @docvia/renderer-react/client.
Plain Vite (React or Svelte)
Without SvelteKit or Next.js, use the same docvia() plugin directly in
vite.config.ts:
import { docvia } from "@docvia/plugin-vite";
import docviaConfig from "./docvia.config";
export default {
plugins: [docvia(docviaConfig)],
};
You can also import a single page directly through the ?docvia transform:
import page from "./docs/index.md?docvia";
Server-side rendering
On the edge or inside a framework app, you usually need nothing extra. The
generated source.ts uses static ?docvia imports, so the page content is
bundled directly into your server output. Importing virtual:docvia/source
(Vite) or docvia/source (Next.js) and calling docs.getPage(...) works at
request time on Cloudflare Workers and other edge runtimes — there is no
node:fs and no Markdown parsing on the request path:
import { docs } from "virtual:docvia/source"; // Next.js: "docvia/source"
const page = await docs.getPage(["getting-started"]); // works on the edge
[!WARNING] Import the collection from server-only modules. The flip side of those static imports is that
virtual:docvia/sourcepulls in every compiled page. That is exactly what you want in a server bundle. In a universal module — a SvelteKit+page.ts, a"use client"component — it means your entire content set is shipped to the browser, silently undoing the bundle-size benefit the compiler exists to provide.Load pages in
+page.server.ts/+layout.server.ts/ a React Server Component, and pass the result down. If you truly need a collection on the client, importvirtual:docvia/source/browser(Next.js:docvia/source/browser) instead — it code-splits one chunk per page and fetches only what you ask for.
For a non-framework Node server that renders per request, use
@docvia/ssr. It renders one document per request and caches
rendered pages in an in-memory LRU keyed by content hash. createDocviaSSR
takes a generic content source — a live CompileService already satisfies the
shape, so pass it directly (or pass a (collection, slug) => IR function):
import { createDocviaSSR } from "@docvia/ssr";
const ssr = createDocviaSSR({ provider: service }); // or (collection, slug) => IR
const page = await ssr.render("docs", "getting-started");
Standalone preview
docvia preview serves the raw .docvia/ output over sirv:
docvia preview --out .docvia --port 4173
This is a sanity check for the compiled module graph — it is not a runtime. For an actual site, use one of the integrations above.
Choosing an approach
| Your app | Integration | Renderer |
|---|---|---|
| SvelteKit | @docvia/plugin-vite (docvia()) | @docvia/renderer-svelte |
| Next.js (webpack or Turbopack) | @docvia/plugin-next | @docvia/renderer-react |
| Plain Vite (Svelte) | @docvia/plugin-vite (docvia()) | @docvia/renderer-svelte |
| Plain Vite (React) | @docvia/plugin-vite (docvia()) | @docvia/renderer-react |
| Request-time / edge SSR | @docvia/ssr | @docvia/renderer-core |
| Any other framework | docvia build + @docvia/source | write a RendererAdapter |