Configuration
Every field of the docs.config.ts file and what it controls.
All configuration lives in one object passed to defineConfig. The helper fills in defaults for the optional fields and returns a ResolvedDocsConfig, so typos and missing required fields are caught at compile time and the UI never has to guess.
import { defineConfig } from "pzzadocs";
export default defineConfig({
title: "PzzaDocs",
description: "A customizable MDX docs framework for Next.js.",
contentDir: "content/docs",
baseUrl: "/docs",
nav: {
links: [
{ text: "Overview", href: "/docs" },
{ text: "Components", href: "/docs/components/callout" },
{ text: "API", href: "/docs/api/config" },
],
github: "https://github.com/pzzaworks/pzza-docs",
},
search: { enabled: true },
theme: { defaultTheme: "system" },
});Fields#
| Field | Type | Default | Description |
|---|---|---|---|
title | string | required | Site name. Rendered as the wordmark next to the logo in the header. |
description | string | none | Short description of the site. Useful as a default for page metadata. |
logo | ReactNode | { src: string; alt?: string; width?: number; height?: number } | none | Header logo. Pass a React element for full control, or an image descriptor. |
contentDir | string | "content/docs" | Folder containing your MDX, relative to process.cwd(). |
baseUrl | string | "/docs" | Route prefix where DocsPage is mounted. Normalized to a leading slash and no trailing slash. |
nav.links | { text: string; href: string; activePrefix?: string; external?: boolean }[] | [] | Horizontal tabs in the header. A tab is active when the current path starts with activePrefix, which defaults to the href. external is inferred from the href when omitted. |
nav.github | string | none | Repository URL. Renders a GitHub icon link on the right side of the header. |
nav.cta | { text: string; href: string } | none | Optional outline button at the far right of the header. |
editUrl | (page: PageData) => string | none | Builds the "Edit on GitHub" link for a page. Receives the page data. |
search.enabled | boolean | true | Shows the search trigger in the header and registers the ⌘K shortcut. |
search.indexUrl | string | "/api/search" | Endpoint the search dialog fetches the JSON index from. |
search.hotKey | string | "k" | Key combined with Meta or Ctrl that opens the dialog. |
theme.defaultTheme | "light" | "dark" | "system" | "system" | Theme used before the visitor picks one. |
theme.hotKey | boolean | true | Pressing D outside an input toggles light and dark. |
toc.minDepth / toc.maxDepth | number | 2 / 3 | Heading depth range collected into the table of contents. |
llm.enabled | boolean | true | Enables the Markdown and llms.txt outputs and the page actions menu. |
llm.markdownPath | (url: string) => string | (url) => `${url}.mdx` | Maps a page URL to the route serving its raw Markdown. |
sidebar.defaultOpenLevel | number | 0 | Folders at this depth or shallower start expanded. |
sidebar.prefetch | boolean | true | Prefetch sidebar links with next/link. |
header.transparentMode | "none" | "top" | "always" | "none" | Transparent header until scroll, always, or never. |
lastModified | "git" | "fs" | false | "git" | Source of the "Last updated" timestamp. |
defaultLocale / locales | string / string[] | none / [] | The source locale and the translated locales. |
localeStrategy | "suffix" | "directory" | "suffix" | Translations as page.de.mdx next to the source, or as one directory per locale under contentDir. |
localePrefix | "never" | "as-needed" | "always" | "never" | Locale segment before baseUrl in page URLs. |
translations | Record<string, Partial<UiLabels>> | none | UI string overrides per locale. |
Localization#
defaultLocale, locales, localeStrategy, localePrefix, and translations configure translated content and UI strings. See Localization for the directory layouts, the resulting URLs, and the route wiring.
Navigation#
nav.links defines the horizontal tabs. Each tab is a plain link. A tab is active when the current pathname starts with its activePrefix, which defaults to the href; set activePrefix when the tab links to the first page of a section so it stays highlighted across the whole section. The most specific match wins, so an Overview tab at /docs does not stay lit on /docs/api/config.
nav: {
links: [
{ text: "Overview", href: "/docs" },
{ text: "Components", href: "/docs/components/callout", activePrefix: "/docs/components" },
{ text: "API", href: "/docs/api/config", activePrefix: "/docs/api" },
],
github: "https://github.com/pzzaworks/pzza-docs",
cta: { text: "Sign in", href: "/login" },
}Logo#
Omit logo to render the title alone. Pass an image descriptor to show an image before the wordmark:
logo: { src: "/logo.svg", alt: "pzzadocs" }Or pass any React element:
logo: <span aria-hidden="true">⌘</span>Keep the config server-safe
docs.config.ts is imported by server code (createSource, DocsLayout) and its theme and search sections are forwarded to the client-side RootProvider. If you use a React element as the logo, keep it free of hooks and browser-only APIs so it renders on the server.
Edit links#
editUrl receives the page and returns a URL. The page object includes the slug and the source file path relative to contentDir, which is usually all you need:
editUrl: (page) =>
`https://github.com/pzzaworks/pzza-docs-web/edit/main/content/docs/${page.file}`,When editUrl is set, every page footer shows a "Last updated" timestamp followed by the edit link.
Search#
Search is client-side and enabled by default. The header shows a "Search..." button with a ⌘K hint, and the dialog fetches the index from search.indexUrl (default /api/search) once, then filters titles, descriptions, and headings as you type. Disable it with search: { enabled: false } if you do not want to expose the index route, or point indexUrl at a static JSON file you generate at build time.
Theme#
theme.defaultTheme is forwarded to the theme provider. "system" follows the operating system preference and switches automatically. The toggle in the header lets visitors override it, and the choice persists in local storage. See Theming for how to restyle the site.