Home /

docs

API Reference

Complete reference for every option in docs.config.ts. All types are exported from @farming-labs/docs.


defineDocs(config)

The entry point for configuring your docs. Returns a typed config object.

docs.config.ts
import { defineDocs } from "@farming-labs/docs";

export default defineDocs({
  entry: "docs",
  // ...all options below
});

DocsConfig

Top-level configuration object passed to defineDocs().

PropertyTypeDefaultDescription
entrystringrequiredURL path prefix for docs (e.g. "docs"/docs)
contentDirstringsame as entryPath to content files. TanStack Start, SvelteKit, Astro, and Nuxt use it; Next.js uses app/{entry}/
staticExportbooleanfalseSet true for full static builds; hides search and AI (see Configuration)
themeDocsThemeTheme preset from a factory (fumadocs(), darksharp(), pixelBorder(), etc.)
githubstring | GithubConfigGitHub repo config for "Edit on GitHub" links
navDocsNavSidebar header title and URL
themeToggleboolean | ThemeToggleConfigtrueLight/dark mode toggle
breadcrumbboolean | BreadcrumbConfigtrueBreadcrumb navigation
sidebarboolean | SidebarConfigtrueSidebar visibility and customization
iconsRecord<string, unknown>Icon registry for frontmatter icon fields
componentsRecord<string, unknown>Custom MDX component overrides, including built-ins like HoverLink
onCopyClick(data: CodeBlockCopyData) => voidCallback when the user clicks the copy button on a code block (runs in addition to copy)
feedbackboolean | FeedbackConfigfalseHuman page feedback UI plus optional agent feedback endpoints
pageActionsPageActionsConfig"Copy Markdown" and "Open in LLM" buttons
aiAIConfigRAG-powered AI chat
searchboolean | DocsSearchConfigtrueBuilt-in simple search, Typesense, Algolia, or a custom adapter
mcpboolean | DocsMcpConfigenabledBuilt-in MCP server over stdio and /api/docs/mcp
apiReferenceboolean | ApiReferenceConfigfalseGenerated API reference pages from supported framework route conventions or a hosted OpenAPI JSON
changelogboolean | ChangelogConfigfalseGenerated changelog feed and entry pages from dated MDX entries
ordering"alphabetical" | "numeric" | OrderingItem[]"alphabetical"Sidebar page ordering strategy
metadataDocsMetadataSEO metadata
ogOGConfigOpen Graph image config

components is merged into the default MDX component map, so you can both add your own components and replace built-ins such as Callout, Tabs, or HoverLink. For built-in defaults like theme.ui.components.HoverLink, see Creating themes. For usage examples and a live demo, see Components.


Ordering

Controls how pages are sorted in the sidebar. Three strategies are available:

"alphabetical" (default)

Pages are sorted alphabetically by folder name. No extra configuration needed.

ordering: "alphabetical",

"numeric"

Pages are sorted by the order field in frontmatter. Lower numbers appear first. Pages without order are sorted alphabetically after ordered pages.

ordering: "numeric",

Then in your page frontmatter:

---
title: "Installation"
order: 1
---

Slug-based (OrderingItem[])

Pass an array of { slug, children? } objects for explicit control over page order, including nested pages.

ordering: [
  { slug: "installation" },
  { slug: "cli" },
  { slug: "configuration" },
  {
    slug: "themes",
    children: [
      { slug: "default" },
      { slug: "darksharp" },
      { slug: "pixel-border" },
      { slug: "creating-themes" },
    ],
  },
  {
    slug: "customization",
    children: [
      { slug: "colors" },
      { slug: "typography" },
      { slug: "sidebar" },
      { slug: "components" },
      { slug: "ai-chat" },
      { slug: "page-actions" },
    ],
  },
  { slug: "reference" },
],

OrderingItem

PropertyTypeDescription
slugstringFolder name at this level (not the full path)
childrenOrderingItem[]Ordering for child pages within this folder

Pages not listed in the array appear alphabetically after the listed ones.


DocsNav

Sidebar header configuration.

PropertyTypeDefaultDescription
titlestring | ReactNode"Docs"Sidebar header title. React elements supported in Next.js and TanStack Start
urlstring"/{entry}"URL the title links to
nav: {
  title: "My Docs",
  url: "/docs",
},

DocsMcpConfig

Built-in MCP server configuration for AI clients, IDE agents, and local MCP tooling.

PropertyTypeDefaultDescription
enabledbooleantrueEnable the MCP server. MCP is on by default; set false to opt out.
routestring"/api/docs/mcp"Streamable HTTP route used by the MCP endpoint
namestringnav.title or @farming-labs/docsMCP server name reported to clients
versionstring"0.0.0"Version string reported to clients
toolsDocsMcpToolsConfigall enabledFine-grained tool toggles
docs.config.ts
export default defineDocs({
  entry: "docs",
  mcp: {
    route: "/api/docs/mcp",
    name: "My Docs MCP",
    tools: {
      listPages: true,
      getNavigation: true,
      searchDocs: true,
      readPage: true,
    },
  },
});

DocsMcpToolsConfig

PropertyTypeDescription
listPagesbooleanExpose the list_pages tool
getNavigationbooleanExpose the get_navigation tool
searchDocsbooleanExpose the search_docs tool
readPagebooleanExpose the read_page tool

Default MCP surface:

Framework notes:

See MCP Server for the route snippets and examples.


DocsSearchConfig

Search is enabled by default. If you do not configure anything, the docs API uses the built-in simple adapter with section-based chunking.

docs.config.ts
export default defineDocs({
  entry: "docs",
  search: true,
});

Built-in providers:

SimpleDocsSearchConfig

PropertyTypeDefaultDescription
provider"simple"impliedUse the built-in search adapter
enabledbooleantrueToggle search on or off
maxResultsnumber10Maximum results to return
chunkingDocsSearchChunkingConfig{ strategy: "section" }Controls whether indexing happens per page or per section
docs.config.ts
search: {
  provider: "simple",
  maxResults: 8,
  chunking: {
    strategy: "section",
  },
},

TypesenseDocsSearchConfig

PropertyTypeDefaultDescription
provider"typesense"Use Typesense as the search backend
baseUrlstringTypesense API base URL
collectionstringCollection name used for docs documents
apiKeystringSearch API key
adminApiKeystringOptional admin key used for on-demand indexing
maxResultsnumber10Maximum results to return
syncOnSearchbooleantrue when adminApiKey is presentRe-index docs on the first search request
queryBystring[]built-in fieldsCustom Typesense query_by fields
mode"keyword" | "hybrid""keyword"Keyword search only, or keyword + embeddings
embeddingsDocsSearchEmbeddingsConfigSemantic embeddings config for hybrid search
chunkingDocsSearchChunkingConfig{ strategy: "section" }Chunking strategy used before indexing/search
docs.config.ts
search: {
  provider: "typesense",
  baseUrl: process.env.TYPESENSE_URL!,
  collection: "docs",
  apiKey: process.env.TYPESENSE_SEARCH_API_KEY!,
  adminApiKey: process.env.TYPESENSE_ADMIN_API_KEY,
  mode: "hybrid",
  embeddings: {
    provider: "ollama",
    model: "embeddinggemma",
  },
},
terminal
pnpm dlx @farming-labs/docs search sync --typesense

AlgoliaDocsSearchConfig

PropertyTypeDefaultDescription
provider"algolia"Use Algolia as the search backend
appIdstringAlgolia application id
indexNamestringAlgolia index name
searchApiKeystringSearch API key
adminApiKeystringOptional admin key used for on-demand indexing
maxResultsnumber10Maximum results to return
syncOnSearchbooleantrue when adminApiKey is presentRe-index docs on the first search request
chunkingDocsSearchChunkingConfig{ strategy: "section" }Chunking strategy used before indexing/search
docs.config.ts
search: {
  provider: "algolia",
  appId: process.env.ALGOLIA_APP_ID!,
  indexName: "docs",
  searchApiKey: process.env.ALGOLIA_SEARCH_API_KEY!,
  adminApiKey: process.env.ALGOLIA_ADMIN_API_KEY,
},
terminal
pnpm dlx @farming-labs/docs search sync --algolia

McpDocsSearchConfig

PropertyTypeDefaultDescription
provider"mcp"Use an MCP endpoint as the search backend
endpointstringStreamable HTTP MCP endpoint
headersRecord<string, string>Extra headers sent to initialize and tool calls
toolNamestring"search_docs"MCP tool name used for search
protocolVersionstring"2025-11-25"MCP protocol version header
maxResultsnumber10Maximum results to request
docs.config.ts
search: {
  provider: "mcp",
  endpoint: "/api/docs/mcp",
},

Relative endpoints are resolved against the current docs API request URL. That makes local setups like the Next example easy to test without hardcoding a host.

CustomDocsSearchConfig

PropertyTypeDescription
provider"custom"Use your own adapter
adapterDocsSearchAdapter | DocsSearchAdapterFactorySearch runtime implementation
maxResultsnumberMaximum results to return
chunkingDocsSearchChunkingConfigChunking strategy used before your adapter runs
docs.config.ts
import { createCustomSearchAdapter, defineDocs } from "@farming-labs/docs";

export default defineDocs({
  entry: "docs",
  search: createCustomSearchAdapter({
    name: "my-search",
    async search(query, context) {
      return context.documents
        .filter((doc) =>
          `${doc.title} ${doc.section ?? ""} ${doc.content}`.toLowerCase().includes(query.query.toLowerCase()),
        )
        .slice(0, query.limit ?? 10)
        .map((doc) => ({
          id: doc.id,
          url: doc.url,
          content: doc.section ? `${doc.title} — ${doc.section}` : doc.title,
          description: doc.description,
          type: doc.type,
          section: doc.section,
        }));
    },
  }),
});

DocsSearchAdapter

Custom adapters receive normalized source pages and chunked search documents so you can focus on retrieval and ranking instead of rebuilding the docs scan pipeline.

search-adapter.ts
import type { DocsSearchAdapter } from "@farming-labs/docs";

export const adapter: DocsSearchAdapter = {
  name: "my-search",
  async search(query, context) {
    return context.documents.map((doc) => ({
      id: doc.id,
      url: doc.url,
      content: doc.section ? `${doc.title} — ${doc.section}` : doc.title,
      description: doc.description,
      type: doc.type,
      section: doc.section,
    }));
  },
};

DocsSearchChunkingConfig

PropertyTypeDefaultDescription
strategy"page" | "section""section"Chunk by whole page or split by headings

DocsSearchEmbeddingsConfig

PropertyTypeDefaultDescription
provider"ollama"Embeddings provider for hybrid Typesense mode
modelstringEmbedding model id
baseUrlstring"http://127.0.0.1:11434"Ollama base URL

Notes:

@farming-labs/theme/api still works for now

@farming-labs/theme/api remains supported as a compatibility import path today, but prefer @farming-labs/next/api in Next.js apps. The theme-level path will be deprecated.


ApiReferenceConfig

Generates API reference pages from framework route conventions or a hosted OpenAPI JSON document.

Use route scanning when the API lives in the same project. Use specUrl when the backend is deployed elsewhere and already exposes an openapi.json.

Current support

apiReference is supported in Next.js, TanStack Start, SvelteKit, Astro, and Nuxt.

Important

apiReference in docs.config controls scanning, theming, routeRoot, and exclude.

In Next.js, withDocs() also generates the route automatically.

In TanStack Start, SvelteKit, Astro, and Nuxt, you must additionally add the framework route handler for /{path}.

Remote spec mode

specUrl is the easiest option when your docs app does not contain the backend route files. Point it at a hosted openapi.json and keep the same themed API reference UI.

PropertyTypeDefaultDescription
enabledbooleantrue inside the objectEnable generated API reference pages
pathstring"api-reference"URL path where the generated API reference lives
specUrlstringAbsolute URL to a hosted OpenAPI JSON document. When set, local route scanning is skipped
routeRootstring"api"Filesystem route root to scan. Bare values like "api" resolve inside app/ or src/app/; full values like "app/internal-api" and "src/app/v2/api" are supported
excludestring[][]Route entries to omit from the generated reference. Accepts URL-style paths like "/api/hello" or route-root-relative values like "hello" / "hello/route.ts"
docs.config.ts
apiReference: {
  enabled: true,
  path: "api-reference",
  routeRoot: "api",
  exclude: ["/api/internal/health", "internal/debug"],
},
docs.config.ts
apiReference: {
  enabled: true,
  path: "api-reference",
  specUrl: "https://petstore3.swagger.io/api/v3/openapi.json",
},

When specUrl is set, routeRoot and exclude are ignored and the API reference is rendered from the hosted spec instead.

This does not remove the framework route requirement on non-Next adapters. TanStack Start, SvelteKit, Astro, and Nuxt still need their /{path} handler files so the docs app has a route that serves the generated API reference page.

When output: "export" is used in Next.js, the generated API reference route is skipped automatically because it requires a server route handler.

Scanned route conventions:

Minimal route handlers for non-Next frameworks:

TanStack Start — src/routes/api-reference.index.ts
import { createFileRoute } from "@tanstack/react-router";
import { createTanstackApiReference } from "@farming-labs/tanstack-start/api-reference";
import docsConfig from "../../docs.config";

const handler = createTanstackApiReference(docsConfig);

export const Route = createFileRoute("/api-reference/")({
  server: {
    handlers: {
      GET: handler,
    },
  },
});

Create a second src/routes/api-reference.$.ts file with the same handler and createFileRoute("/api-reference/$").

SvelteKit — src/routes/api-reference/+server.ts
import { createSvelteApiReference } from "@farming-labs/svelte/api-reference";
import config from "$lib/docs.config";

export const GET = createSvelteApiReference(config);

Create src/routes/api-reference/[...slug]/+server.ts with the same GET export.

Astro — src/pages/api-reference/index.ts
import { createAstroApiReference } from "@farming-labs/astro/api-reference";
import config from "../../lib/docs.config";

export const GET = createAstroApiReference(config);

Create src/pages/api-reference/[...slug].ts with the same GET export.

Nuxt — server/routes/api-reference/index.ts
import { defineApiReferenceHandler } from "@farming-labs/nuxt/api-reference";
import config from "~/docs.config";

export default defineApiReferenceHandler(config);

Create server/routes/api-reference/[...slug].ts with the same default export.


ChangelogConfig

Generates changelog listing and entry pages from dated MDX folders inside the docs content tree.

Current support

The turn-key generated changelog pages are currently wired in Next.js when you use withDocs().

PropertyTypeDefaultDescription
enabledbooleantrue inside the objectEnable generated changelog pages
pathstring"changelog"URL path where the changelog listing lives inside the docs layout
contentDirstring"changelog"Source directory under the docs content root. Example: app/docs/changelog/2026-03-04/page.mdx
titlestring"Changelog"Listing page title
descriptionstringListing page description shown in the header and metadata
searchbooleantrueShow the built-in changelog search field
actionsComponentReactNode | ComponentCustom action content rendered in the changelog rail
docs.config.ts
changelog: {
  enabled: true,
  path: "changelogs",
  contentDir: "changelog",
  title: "Changelog",
  description: "Latest product updates and release notes.",
  search: true,
},

With entry: "docs" and the config above, the public pages render at:

When you use withDocs(), the route files are generated automatically. There is no separate __changelog.generated.tsx file to maintain.

ChangelogFrontmatter

Optional frontmatter fields for each changelog entry:

PropertyTypeDescription
titlestringEntry title shown in the feed and entry page
descriptionstringShort summary shown in the feed and metadata
imagestringCover image path or URL
authorsstring | string[]Author name(s) shown in entry meta
versionstringCompact version badge like v0.1.0
tagsstring[]Badge list shown in the feed and entry page
pinnedbooleanKeep important entries pinned to the top of the listing
draftbooleanHide the entry from generated routes and search indexes
---
title: "OpenAPI mode is now the default"
description: "The docs example now ships with the faster API reference experience."
version: "v0.1.13"
tags: ["api-reference", "next"]
---

GithubConfig

GitHub repository configuration. Enables "Edit on GitHub" links in page footers.

PropertyTypeDefaultDescription
urlstringrequiredRepository URL (e.g. "https://github.com/my-org/repo")
branchstring"main"Branch name
directorystringContent subdirectory for monorepos
// Simple
github: "https://github.com/my-org/my-docs",

// Monorepo
github: {
  url: "https://github.com/my-org/monorepo",
  branch: "main",
  directory: "apps/docs/docs",
},

The "Edit on GitHub" link only appears when both url and directory are provided.


onCopyClick and CodeBlockCopyData

Optional callback on DocsConfig. Fired when the user clicks the copy button on a code block — in addition to copying to the clipboard. Use it for analytics, logging, or custom behavior. See Code block copy callback for setup (Next.js / TanStack Start vs SvelteKit / Astro / Nuxt).

CodeBlockCopyData

Argument passed to onCopyClick(data: CodeBlockCopyData).

PropertyTypeDescription
titlestring | undefinedCode block title (e.g. from fenced code meta), if present
contentstringRaw code content (what was copied)
urlstringCurrent page URL at the time of copy
languagestring | undefinedLanguage/syntax hint (e.g. "tsx", "bash"), if present
docs.config.ts
import type { CodeBlockCopyData } from "@farming-labs/docs";
import { defineDocs } from "@farming-labs/docs";

export default defineDocs({
  entry: "docs",
  onCopyClick(data: CodeBlockCopyData) {
    // data.title, data.content, data.url, data.language
    console.log("Copied:", data.language, data.title ?? "(no title)");
  },
});

feedback, FeedbackConfig, AgentFeedbackConfig, and feedback payloads`

Optional docs page feedback UI. When enabled, a built-in "Good / Bad" prompt is rendered at the end of the page and emits a feedback payload when the user clicks one of the buttons.

FeedbackConfig

PropertyTypeDefaultDescription
enabledbooleantrueShow or hide the feedback UI
questionstring"How is this guide?"Prompt shown above the buttons
positiveLabelstring"Good"Label for the positive button
negativeLabelstring"Bad"Label for the negative button
onFeedback(data: DocsFeedbackData) => voidCallback fired when the user clicks a button
agentboolean | AgentFeedbackConfigAgent feedback routes served through /api/docs

DocsFeedbackData

PropertyTypeDescription
value"positive" | "negative"Which feedback button the user clicked
titlestring | undefinedCurrent page title, when available
descriptionstring | undefinedCurrent page description, when available
urlstringFull current page URL
pathnamestringCurrent pathname without origin
pathstringAlias of pathname
entrystringDocs entry root, e.g. "docs"
slugstringPage slug relative to the docs entry
localestring | undefinedActive locale when docs i18n is enabled
docs.config.ts
import type { DocsFeedbackData } from "@farming-labs/docs";
import { defineDocs } from "@farming-labs/docs";

export default defineDocs({
  entry: "docs",
  feedback: {
    enabled: true,
    onFeedback(data: DocsFeedbackData) {
      console.log("Feedback:", data.value, data.slug, data.url);
    },
  },
});

This docs site persists feedback through a local Next.js route at website/app/api/feedback/route.ts, backed by the DocsFeedback Prisma model in website/prisma/schema.prisma.

See Page feedback for framework-specific notes. The built-in UI does not require a separate client bridge file.

AgentFeedbackConfig

Optional machine-facing feedback routes for agents, scripts, or evaluation flows.

PropertyTypeDefaultDescription
enabledbooleantrue when agent is providedEnable or disable the agent feedback endpoints
routestring"/api/docs/agent/feedback"Public HTTP route for feedback submission
schemaRoutestring${route}/schemaPublic HTTP route for the machine-readable schema
schemaRecord<string, unknown>built-in payload schemaSchema used to validate the payload object
onFeedback(data: DocsAgentFeedbackData) => Promise<void> | voidAsync callback fired after a valid submission

Notes:

DocsAgentFeedbackContext

PropertyTypeDescription
pagestring | undefinedDocs page path such as "/docs/installation"
urlstring | undefinedFull docs URL when available
slugstring | undefinedDocs slug relative to the entry root
localestring | undefinedActive locale when docs i18n is enabled
sourcestring | undefinedArbitrary source label such as "md-route", "mcp", or "api"

DocsAgentFeedbackData

PropertyTypeDescription
contextDocsAgentFeedbackContext | undefinedOptional docs/page transport context
payloadRecord<string, unknown>Agent feedback payload validated by feedback.agent.schema
docs.config.ts
import { defineDocs } from "@farming-labs/docs";

export default defineDocs({
  entry: "docs",
  feedback: {
    agent: {
      enabled: true,
      route: "/api/docs/agent/feedback",
      async onFeedback(data) {
        console.log(data.context?.page, data.payload);
      },
    },
  },
});
default request body
{
  "context": {
    "page": "/docs/installation",
    "source": "md-route"
  },
  "payload": {
    "task": "install docs in an existing Next.js app",
    "understanding": "partial",
    "outcome": "implemented",
    "confidence": 0.78
  }
}

Quick checks:

curl "http://127.0.0.1:3000/.well-known/agent.json"

curl "http://127.0.0.1:3000/api/docs/agent/feedback/schema"

curl -X POST "http://127.0.0.1:3000/api/docs/agent/feedback" \
  -H "content-type: application/json" \
  -d '{"payload":{"task":"demo","outcome":"implemented"}}'

ThemeToggleConfig

Light/dark mode toggle in the sidebar.

PropertyTypeDefaultDescription
enabledbooleantrueShow or hide the toggle
default"light" | "dark" | "system""system"Forced theme when enabled: false
mode"light-dark" | "light-dark-system""light-dark"Toggle behavior
// Show toggle (default)
themeToggle: true,

// Hide toggle, follow system preference
themeToggle: false,

// Hide toggle, force dark mode
themeToggle: { enabled: false, default: "dark" },

// Show toggle with system option
themeToggle: { mode: "light-dark-system" },

Breadcrumb navigation above page content.

PropertyTypeDefaultDescription
enabledbooleantrueShow or hide breadcrumbs
componentComponentCustom breadcrumb component (Next.js only)
breadcrumb: true,              // show (default)
breadcrumb: false,             // hide
breadcrumb: { enabled: false },  // hide

SidebarConfig

Sidebar visibility and customization. See Sidebar for the full guide including custom sidebar components.

PropertyTypeDefaultDescription
enabledbooleantrueShow or hide the sidebar
component(props: SidebarComponentProps) => ReactNodeCustom sidebar render function. Receives { tree, collapsible, flat }. Supported in Next.js and TanStack Start — other frameworks use slots.
footerReactNodeContent rendered below nav items
bannerReactNodeContent rendered above nav items
collapsiblebooleantrueWhether sidebar is collapsible on desktop
flatbooleanfalseRender all items flat (Mintlify-style, no collapsible groups)

SidebarComponentProps

Props passed to a custom sidebar component:

PropertyTypeDescription
treeSidebarTreeFull page tree with all parent-child relationships
collapsiblebooleanWhether folders are collapsible
flatbooleanWhether folders are rendered flat

SidebarTree

PropertyTypeDescription
namestringRoot name (e.g. "Docs")
childrenSidebarNode[]Top-level sidebar items

SidebarNode

A union of SidebarPageNode | SidebarFolderNode.

SidebarPageNode

PropertyTypeDescription
type"page"Node type
namestringDisplay name
urlstringPage URL
iconunknownIcon from registry

SidebarFolderNode

PropertyTypeDescription
type"folder"Node type
namestringDisplay name
iconunknownIcon from registry
indexSidebarPageNodeFolder's landing page
childrenSidebarNode[]Child pages and sub-folders
collapsiblebooleanWhether this folder collapses
defaultOpenbooleanWhether it starts open
sidebar: true,                     // show (default)
sidebar: false,                    // hide
sidebar: { collapsible: false },   // non-collapsible
sidebar: { flat: true },           // Mintlify-style flat
sidebar: {                         // custom component
  component: ({ tree }) => <MySidebar tree={tree} />,
},

DocsTheme

Theme configuration returned by theme factories.

PropertyTypeDescription
namestringTheme identifier (e.g. "fumadocs", "darksharp")
uiUIConfigVisual configuration — colors, typography, layout

Created via theme factories:

import { fumadocs } from "@farming-labs/theme";
import { darksharp } from "@farming-labs/theme/darksharp";
import { pixelBorder } from "@farming-labs/theme/pixel-border";
import { colorful } from "@farming-labs/theme/colorful";

theme: fumadocs({ ui: { /* overrides */ } }),
import { fumadocs } from "@farming-labs/theme";
import { darksharp } from "@farming-labs/theme/darksharp";
import { pixelBorder } from "@farming-labs/theme/pixel-border";
import { colorful } from "@farming-labs/theme/colorful";

theme: fumadocs({ ui: { /* overrides */ } }),
import { fumadocs, darksharp, pixelBorder } from "@farming-labs/svelte-theme";
import { colorful } from "@farming-labs/svelte-theme/colorful";

theme: fumadocs({ ui: { /* overrides */ } }),
import { fumadocs } from "@farming-labs/astro-theme";
import { pixelBorder } from "@farming-labs/astro-theme/pixel-border";
import { darksharp } from "@farming-labs/astro-theme/darksharp";
import { colorful } from "@farming-labs/astro-theme/colorful";

theme: fumadocs({ ui: { /* overrides */ } }),
import { fumadocs } from "@farming-labs/nuxt-theme/fumadocs";
import { colorful } from "@farming-labs/nuxt-theme/colorful";

theme: fumadocs({ ui: { /* overrides */ } }),

UIConfig

Fine-grained visual configuration passed to theme factories.

PropertyTypeDescription
colorsColorsConfigTheme color tokens
typographyTypographyConfigFont families, heading styles
radiusstringGlobal border-radius (e.g. "0px", "0.5rem")
layoutLayoutConfigContent width, sidebar width, TOC settings
codeBlockCodeBlockConfigSyntax highlighting and line numbers
sidebarSidebarStyleConfigSidebar visual style
cardCardConfigCard component styling

ColorsConfig

All color tokens. Accepts any CSS color value (hex, rgb, oklch, hsl).

TokenDescription
primaryPrimary brand color
primaryForegroundText color on primary backgrounds
backgroundPage background
foregroundDefault text color
mutedMuted background (e.g. code blocks)
mutedForegroundText on muted backgrounds
borderDefault border color
cardCard background
cardForegroundCard text color
accentAccent color
accentForegroundText on accent backgrounds
secondarySecondary color
secondaryForegroundText on secondary backgrounds
popoverPopover/dropdown background
popoverForegroundPopover text color
ringFocus ring color
colors: {
  primary: "oklch(0.72 0.19 149)",
  background: "hsl(0 0% 2%)",
  border: "#262626",
},

LayoutConfig

PropertyTypeDefaultDescription
contentWidthnumberMax width of content area in px
sidebarWidthnumberSidebar width in px
tocWidthnumberTable of contents width in px
toc.enabledbooleantrueShow table of contents
toc.depthnumber3Max heading depth for TOC
header.heightnumberHeader height in px
header.stickybooleantrueSticky header

CodeBlockConfig

PropertyTypeDefaultDescription
showLineNumbersbooleanfalseShow line numbers
showCopyButtonbooleantrueShow copy button
themestringShiki theme for light mode
darkThemestringShiki theme for dark mode

SidebarStyleConfig

PropertyTypeDefaultDescription
style"default" | "bordered" | "floating""default"Sidebar visual style
backgroundstringBackground color override
borderColorstringBorder color override

TypographyConfig

typography: {
  font: {
    style: {
      sans: "Inter, sans-serif",
      mono: "JetBrains Mono, monospace",
    },
    h1: { size: "2.25rem", weight: 700, letterSpacing: "-0.02em" },
    h2: { size: "1.75rem", weight: 600 },
    h3: { size: "1.25rem", weight: 600 },
    body: { size: "1rem", lineHeight: "1.75" },
    small: { size: "0.875rem" },
  },
},

FontStyle

Used for each heading level and body text.

PropertyTypeDescription
sizestringCSS font-size (e.g. "2.25rem", "clamp(1.8rem, 3vw, 2.5rem)")
weightstring | numberCSS font-weight (e.g. 700, "bold")
lineHeightstringCSS line-height (e.g. "1.2", "28px")
letterSpacingstringCSS letter-spacing (e.g. "-0.02em")

AIConfig

RAG-powered AI chat. See Ask AI for usage guide.

PropertyTypeDefaultDescription
enabledbooleanfalseEnable AI chat
mode"search" | "floating""search"UI mode: integrated in search or floating widget
position"bottom-right" | "bottom-left" | "bottom-center""bottom-right"Floating button position (only when mode: "floating")
floatingStyle"panel" | "modal" | "popover" | "full-modal""panel"Floating chat visual style
triggerComponentComponentCustom floating button component
modelstring"gpt-4o-mini"LLM model name (OpenAI-compatible)
systemPromptstringauto-generatedCustom system prompt
baseUrlstring"https://api.openai.com/v1"OpenAI-compatible API base URL
apiKeystringprocess.env.OPENAI_API_KEYAPI key for the LLM provider
maxResultsnumber5Number of doc pages to include as RAG context
suggestedQuestionsstring[]Pre-filled questions shown when chat is empty
aiLabelstring"AI"Display name for the AI assistant
packageNamestringPackage name the AI uses in import examples
docsUrlstringBase URL the AI uses for links
loaderstring"shimmer-dots"Loading indicator variant ("shimmer-dots", "circular", "dots", "typing", "wave", "bars", "pulse", "pulse-dot", "terminal", "text-blink", "text-shimmer", "loading-dots")
loadingComponent(props: { name: string }) => ReactNodeCustom loading component (overrides loader, Next.js only)

Floating styles

StyleDescription
"panel"Tall panel sliding up from the button. No backdrop.
"modal"Centered modal with backdrop overlay, like Cmd+K search.
"popover"Compact popover near the button.
"full-modal"Full-screen immersive overlay with pills for suggested questions.

PageActionsConfig

Action buttons shown on each docs page. See Page Actions for usage guide.

PropertyTypeDefaultDescription
position"above-title" | "below-title""below-title"Where to render the buttons
alignment"left" | "right""left"Horizontal alignment of the action row
copyMarkdownboolean | CopyMarkdownConfigfalse"Copy Markdown" button
openDocsboolean | OpenDocsConfigfalse"Open in LLM" dropdown

CopyMarkdownConfig

PropertyTypeDefaultDescription
enabledbooleanfalseShow the button

OpenDocsConfig

PropertyTypeDefaultDescription
enabledbooleanfalseShow the dropdown
providersOpenDocsProvider[]ChatGPT, ClaudeLLM/tool providers

OpenDocsProvider

PropertyTypeDescription
namestringDisplay name (e.g. "ChatGPT", "Claude")
iconReactNodeIcon rendered next to the name
urlTemplatestringURL template. {url} is replaced with the page URL, {mdxUrl} with the raw MDX source URL, and {githubUrl} with the GitHub edit URL when github is configured. Use {url}.md when you want the public machine-readable page route.
pageActions: {
  copyMarkdown: { enabled: true },
  openDocs: {
    enabled: true,
    providers: [
      { name: "ChatGPT", urlTemplate: "https://chatgpt.com/?q={url}" },
      { name: "Claude", urlTemplate: "https://claude.ai/new?q=Read+this:+{url}" },
    ],
  },
},

DocsMetadata

SEO metadata configuration.

PropertyTypeDefaultDescription
titleTemplatestringPage title template. %s is replaced with the page title.
descriptionstringDefault meta description
twitterCard"summary" | "summary_large_image"Twitter card type
metadata: {
  titleTemplate: "%s – My Docs",
  description: "Documentation for my project",
},

OGConfig

Open Graph image configuration. When endpoint is set, each docs page gets a dynamic OG image: the framework passes the page’s title and description (from frontmatter) to the endpoint, and the layout injects the resulting image URL into og:image and twitter:image meta tags. For a full guide (how dynamic OG works, what context is passed, and how the docs website implements it), see OG Images.

PropertyTypeDefaultDescription
enabledbooleanfalseEnable OG image generation
type"static" | "dynamic"Static images or dynamic generation
endpointstringAPI endpoint for dynamic OG images
defaultImagestringFallback OG image URL

Example (Next.js): In docs.config.ts, set og.endpoint to your OG route path. Then implement app/api/og/route.tsx (or route.ts) that accepts title and description query params and returns a 1200×630 image (e.g. using ImageResponse from next/og).

og: {
  enabled: true,
  type: "dynamic",
  endpoint: "/api/og",
},

Testing your OG image

  1. Start the dev server for the app that serves the OG route (e.g. cd website && pnpm dev or cd examples/next && pnpm dev).
  2. Open the OG URL in the browser, e.g.
    http://localhost:3000/api/og?title=Test&description=My+description
    (use your app’s port if different).
  3. After changing the OG route code, refresh the page. If the image doesn’t update, do a hard refresh (e.g. Cmd+Shift+R on macOS, Ctrl+Shift+R on Windows) or open the URL in a private/incognito window. You can also add a cache-busting query param (e.g. &_=1, &_=2) to force a new request.

Page Frontmatter

Each docs page (.mdx / .md) supports these frontmatter fields:

PropertyTypeDescription
titlestringRequired. Page title, shown in sidebar and page heading
descriptionstringPage description, used for meta tags and search
iconstringIcon key from the icons registry. Shows in sidebar.
ordernumberSort order in the sidebar (only when ordering: "numeric"). Lower numbers first.
tagsstring[]Tags for categorization
ogImagestringShorthand for a single OG image path. Ignored if openGraph is set.
openGraphPageOpenGraphFull Open Graph object (e.g. images: [{ url, width?, height? }]). When set, replaces generated OG from the config (e.g. dynamic endpoint).
twitterPageTwitterFull Twitter card object (e.g. card, images). When set, replaces generated twitter metadata.
hiddenbooleanIf true, hide the page from the sidebar (page remains reachable by URL). Optional; behavior may vary by adapter.

Static OG example — use openGraph and twitter in frontmatter to serve a static image instead of the dynamic OG endpoint:

page-frontmatter.md
---
title: "Title of Docs"
description: "Title of the docs goes here"
icon: "harddrive"
openGraph:
  images:
    - url: "/og/path-to-image/image.png"
      width: 1200
      height: 630
twitter:
  card: "summary_large_image"
  images:
    - "/og/path-to-image/image.png"
---

Minimal example (shorthand ogImage or generated OG):

page.md
---
title: "Getting Started"
description: "Set up your docs in 5 minutes"
icon: "rocket"
order: 1
---

Data types

Frontmatter is YAML between the --- fences. Supported value types:

TypeExample in frontmatterUse in framework fields
stringtitle: "Hello" or title: Hellotitle, description, icon, ogImage
numberorder: 1order
booleanhidden: trueOptional (e.g. hide from sidebar)
string[]tags: [a, b] or tags: ["a", "b"]tags

You can use other YAML types (e.g. nested objects) for custom keys; only the fields in the table above are used by the framework for sidebar, SEO, and OG.

How frontmatter is passed

So in all frameworks, the same frontmatter fields drive titles, descriptions, icons, ordering, and OG; only the mechanism (MDX metadata vs. content loader page.data) differs.


createTheme(options)

Create a custom theme from scratch. See Creating Themes.

import { createTheme } from "@farming-labs/docs";

export const myTheme = createTheme({
  name: "my-theme",
  ui: {
    colors: { primary: "#ff4d8d", background: "#0a0a0a" },
    radius: "0px",
    sidebar: { style: "bordered" },
  },
});

extendTheme(base, overrides)

Extend an existing theme with overrides.

import { extendTheme } from "@farming-labs/docs";
import { fumadocs } from "@farming-labs/theme";

export const myTheme = extendTheme(fumadocs(), {
  ui: {
    colors: { primary: "oklch(0.72 0.19 149)" },
  },
});

TanStack Start Server API

createDocsServer(config)

Creates the TanStack Start docs server adapter.

import { createDocsServer } from "@farming-labs/tanstack-start/server";

Parameters:

PropertyTypeDescription
configDocsConfigThe config object from defineDocs()
rootDirstringOptional project root used to resolve contentDir. Defaults to process.cwd()

Returns:

PropertyTypeDescription
load({ pathname, locale? }) => Promise<DocsServerLoadResult>Loads docs page data and the sidebar tree for a pathname
GET({ request }) => ResponseSearch / markdown / llms.txt endpoint handler
POST({ request }) => Promise<Response>AI chat endpoint handler
src/lib/docs.server.ts
import { createDocsServer } from "@farming-labs/tanstack-start/server";
import docsConfig from "../../docs.config";

export const docsServer = createDocsServer({
  ...docsConfig,
  rootDir: process.cwd(),
});

TanStack Start Components

ComponentImportDescription
TanstackDocsPage@farming-labs/tanstack-start/reactBuilt-in page renderer that resolves the compiled MDX module and wraps it in the shared docs layout
RootProvider@farming-labs/theme/tanstackRoot provider for theme state, search, and AI UI
src/routes/docs.index.tsx
import { createFileRoute } from "@tanstack/react-router";
import { TanstackDocsPage } from "@farming-labs/tanstack-start/react";
import { loadDocPage } from "@/lib/docs.functions";
import docsConfig from "../../docs.config";

export const Route = createFileRoute("/docs/")({
  loader: () => loadDocPage({ data: { pathname: "/docs" } }),
  component: DocsIndexPage,
});

function DocsIndexPage() {
  const data = Route.useLoaderData();
  return <TanstackDocsPage config={docsConfig} data={data} />;
}
src/routes/api.docs.ts
import { createFileRoute } from "@tanstack/react-router";
import { docsServer } from "@/lib/docs.server";

export const Route = createFileRoute("/api/docs")({
  server: {
    handlers: {
      GET: async ({ request }) => docsServer.GET({ request }),
      POST: async ({ request }) => docsServer.POST({ request }),
    },
  },
});

TanStack Start also uses the docsMdx() Vite plugin from @farming-labs/tanstack-start/vite so .mdx files compile without extra local module-loader glue.


SvelteKit Server API

createDocsServer(config)

Creates all server-side functions for a SvelteKit docs site.

import { createDocsServer } from "@farming-labs/svelte/server";

Parameters:

PropertyTypeDescription
configDocsConfigThe config object from defineDocs()
_preloadedContentRecord<string, string>Pre-loaded markdown files from import.meta.glob. Required for serverless.

Returns:

PropertyTypeDescription
load(event) => Promise<PageData>Layout load function (use in +layout.server.js)
GET(event) => ResponseSearch endpoint handler
POST(event) => Promise<Response>AI chat endpoint handler
src/lib/docs.server.ts
import { createDocsServer } from "@farming-labs/svelte/server";
import config from "./docs.config";

const contentFiles = import.meta.glob("/docs/**/*.{md,mdx,svx}", {
  query: "?raw",
  import: "default",
  eager: true,
}) as Record<string, string>;

export const { load, GET, POST } = createDocsServer({
  ...config,
  _preloadedContent: contentFiles,
});

SvelteKit Components

Imported from @farming-labs/svelte-theme:

ComponentPropsDescription
DocsLayouttree, config, title?, titleUrl?Main layout with sidebar, nav, search, AI
DocsContentdata, configPage content with TOC, breadcrumb, footer nav
DocsPageentry, tocEnabled, breadcrumbEnabled, previousPage, nextPage, editOnGithub, lastModifiedLow-level page wrapper (used by DocsContent)

Astro Server API

createDocsServer(config)

Same as SvelteKit — returns { load, GET, POST }.

src/lib/docs.server.ts
import { createDocsServer } from "@farming-labs/astro/server";

Parameters:

PropertyTypeDescription
configDocsConfigThe config object from defineDocs()
_preloadedContentRecord<string, string>Pre-loaded markdown files from import.meta.glob. Required for serverless.

Returns:

PropertyTypeDescription
load(pathname: string) => Promise<PageData>Takes a URL pathname string, returns page data
GET({ request }) => ResponseSearch endpoint handler for GET /api/docs?query=...
POST({ request }) => Promise<Response>AI chat endpoint handler with SSE streaming
src/lib/docs.server.ts
import { createDocsServer } from "@farming-labs/astro/server";
import config from "./docs.config";

const contentFiles = import.meta.glob("/docs/**/*.{md,mdx}", {
  query: "?raw",
  import: "default",
  eager: true,
}) as Record<string, string>;

export const { load, GET, POST } = createDocsServer({
  ...config,
  _preloadedContent: contentFiles,
});

Astro Components

ComponentImportDescription
DocsLayout@farming-labs/astro-theme/src/components/DocsLayout.astroMain layout with sidebar, search, and theme toggle
DocsContent@farming-labs/astro-theme/src/components/DocsContent.astroPage content with metadata
DocsPage@farming-labs/astro-theme/src/components/DocsPage.astroPage structure (TOC, breadcrumb, nav)
ThemeToggle@farming-labs/astro-theme/src/components/ThemeToggle.astroLight/dark toggle
SearchDialog@farming-labs/astro-theme/src/components/SearchDialog.astroSearch + AI dialog

CSS Imports

Same pattern as SvelteKit:

ImportDescription
@farming-labs/astro-theme/cssDefault (fumadocs) theme
@farming-labs/astro-theme/pixel-border/cssPixel border theme
@farming-labs/astro-theme/darksharp/cssDarksharp theme

Theme Factories

FactoryImport
fumadocs()@farming-labs/astro-theme
pixelBorder()@farming-labs/astro-theme/pixel-border
darksharp()@farming-labs/astro-theme/darksharp

Nuxt Server API

defineDocsHandler(config, useStorage)

Creates a single Nitro event handler that serves docs loading, search, and AI chat for Nuxt.

import { defineDocsHandler } from "@farming-labs/nuxt/server";

Parameters:

PropertyTypeDescription
configDocsConfigThe config object from defineDocs()
useStorageFunctionNitro's useStorage utility for accessing server assets

Returns:

A Nitro event handler that responds to GET (page loading + search) and POST (AI chat) requests.

server/api/docs.ts
import { defineDocsHandler } from "@farming-labs/nuxt/server";
import config from "../../docs.config";

export default defineDocsHandler(config, useStorage);

Nuxt uses Nitro's serverAssets to load markdown files. Configure nitro.serverAssets in nuxt.config.ts to point to your docs directory.

Nuxt Components

Imported from @farming-labs/nuxt-theme:

ComponentPropsDescription
DocsLayouttree, config, triggerComponent?Main layout with sidebar, nav, search, AI
DocsContentdata, configPage content with TOC, breadcrumb, footer nav

CSS Imports

ImportDescription
@farming-labs/nuxt-theme/fumadocs/cssDefault (fumadocs) theme

Theme Factories

FactoryImport
fumadocs()@farming-labs/nuxt-theme/fumadocs

Next.js API

RootProvider

Client-side provider that wraps your entire app. Enables search, theme switching (light/dark), and AI chat. Must be placed in your root app/layout.tsx.

app/layout.tsx
import { RootProvider } from "@farming-labs/theme";
import "./global.css";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <RootProvider>{children}</RootProvider>
      </body>
    </html>
  );
}
PropTypeDefaultDescription
searchSearchProviderProps{ options: { api: "/api/docs" } }Search configuration. API defaults to the unified docs handler.
themeThemeProviderPropsTheme provider options (passed to next-themes)
childrenReactNoderequiredYour app content

suppressHydrationWarning on <html> prevents React warnings caused by the theme class being injected before hydration.

withDocs(nextConfig)

Wraps your Next.js config with docs framework support. Handles MDX, routing, search index generation, and auto-generates mdx-components.tsx and app/docs/layout.tsx if missing.

next.config.ts
import { withDocs } from "@farming-labs/next/config";
export default withDocs({});

createDocsLayout(config)

Creates the docs layout component from your config. Auto-generated by withDocs() — you typically don't need to create this manually.

app/docs/layout.tsx
import { createDocsLayout } from "@farming-labs/theme";
import config from "@/docs.config";

const { DocsLayout } = createDocsLayout(config);

export default function Layout({ children }) {
  return <DocsLayout>{children}</DocsLayout>;
}