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.

docs.config.ts
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#

FieldTypeDefaultDescription
titlestringrequiredSite name. Rendered as the wordmark next to the logo in the header.
descriptionstringnoneShort description of the site. Useful as a default for page metadata.
logoReactNode | { src: string; alt?: string; width?: number; height?: number }noneHeader logo. Pass a React element for full control, or an image descriptor.
contentDirstring"content/docs"Folder containing your MDX, relative to process.cwd().
baseUrlstring"/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.githubstringnoneRepository URL. Renders a GitHub icon link on the right side of the header.
nav.cta{ text: string; href: string }noneOptional outline button at the far right of the header.
editUrl(page: PageData) => stringnoneBuilds the "Edit on GitHub" link for a page. Receives the page data.
search.enabledbooleantrueShows the search trigger in the header and registers the ⌘K shortcut.
search.indexUrlstring"/api/search"Endpoint the search dialog fetches the JSON index from.
search.hotKeystring"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.hotKeybooleantruePressing D outside an input toggles light and dark.
toc.minDepth / toc.maxDepthnumber2 / 3Heading depth range collected into the table of contents.
llm.enabledbooleantrueEnables 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.defaultOpenLevelnumber0Folders at this depth or shallower start expanded.
sidebar.prefetchbooleantruePrefetch 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 / localesstring / 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.
translationsRecord<string, Partial<UiLabels>>noneUI 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.

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.

ts
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" },
}

Omit logo to render the title alone. Pass an image descriptor to show an image before the wordmark:

ts
logo: { src: "/logo.svg", alt: "pzzadocs" }

Or pass any React element:

tsx
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.

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:

ts
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 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.