# Documentation > A modern, flexible MDX documentation framework for Next.js, SvelteKit, Astro, and Nuxt. ## Introduction URL: https://farming-labs-docs.vercel.app/docs A modern, flexible documentation framework that just works @farming-labs/docs A modern documentation framework built on top of Fumadocs and other preset providers. One config file, zero boilerplate, beautiful themes out of the box. Why @farming-labs/docs? - Zero boilerplate — No layout files, no [[...slug]] wrappers except for fully fledged functionality like AI, Search and metadata to work. Just write Markdown or MDX. - One config — Everything in docs.config.ts: theme, colors, typography, icons, components, metadata. - Token efficient — Your entire docs framework surface is a single config file (~15 lines). AI tools like Cursor, Copilot, and Claude spend less time reading framework plumbing and more time working with your actual content. Built-in llms.txt serves your docs in LLM-optimized format automatically. Learn more → - Multiple frameworks — First-class support for Next.js, SvelteKit, Astro, and Nuxt that just works. - 7 themes — Default, Darksharp, Pixel Border, Colorful, Shiny, DarkBold, and GreenTree — or build your own with createTheme(). - Built-in search — Full-text search powered by Orama. No API keys. - CLI scaffolding — npx @farming-labs/docs@latest init detects your framework, generates config, installs deps, starts dev. Use --template to bootstrap a new project with one command. other docs frameworks? We are not trying to replace Fumadocs — we aim to be complementary. @farming-labs/docs builds on Fumadocs (and other providers) to offer a single config, multi-framework support, and optional themes and tooling, so you can use Fumadocs with less boilerplate and across Next.js, SvelteKit, Astro, and Nuxt. If you're choosing between documentation tools, here’s when @farming-labs/docs is a good fit: - vs. Fumadocs alone — You get the same UI and MDX experience, but with a single docs.config and first-class support for SvelteKit, Astro, and Nuxt — not just Next.js. One config model and CLI so you don’t wire layouts, themes, and search by hand. - vs. Docusaurus / VitePress — You keep full control inside your existing app (Next, SvelteKit, Astro, Nuxt) instead of a separate docs site. No separate framework or build; your docs live in the same repo and stack, with one config file and optional built-in AI chat and search. - vs. Mintlify / ReadMe / hosted docs — You own the code and hosting. No vendor lock-in or per-seat pricing; you can deploy to Vercel, Cloudflare Pages, or anywhere. Built-in llms.txt and AI chat give you AI-friendly docs without a third-party docs platform. - vs. hand-rolled MDX — No need to build layouts, catch-all routes, search, or theming yourself. The CLI scaffolds everything; you spend time on content and optional customization (themes, colors, sidebar, page actions) instead of framework plumbing. In short: use @farming-labs/docs when you want one config, multiple frameworks, minimal boilerplate, and optional AI/search built in — without leaving your current stack or adopting a separate docs-only framework. Customize themes and share them You can create your own theme and distribute it to others — as an npm package, a shared preset, or a CSS file. Themes control layout, colors, typography, and components; once built, anyone can plug them in via config. See Themes for built-in presets and Creating themes for the full API. Built-in docs UI — enable and customize from config Modern docs features are built in; you turn them on in configuration instead of wiring them yourself. Each element can be customized — layout, behavior, and appearance — via the same config and theme options. See Customization for the full overview. - Ask AI — RAG-powered chat, multiple models and providers, floating or sidebar mode. Customize labels, suggested questions, model list, and UI mode. - Search — Full-text search (Orama) is included by default; configure via configuration. - Page actions — Copy Markdown, open in ChatGPT/other tools. Customize which actions appear and their options. - Sidebar — Collapsible, flat or nested, banner, footer. Customize structure, style, and content (banner, footer, nav title). - llms.txt — LLM-friendly index of your docs; served when the docs API is enabled. Options described in the llms.txt docs. Theme-level customization (colors, typography, components) is covered in Configuration and Customization (including Colors and Typography). No custom components or routes required — enable and tweak what you need in docs.config. Packages | Package | Description | | ---------------------------- | ------------------------------------------------------------------------------------ | | @farming-labs/docs | Core types, defineDocs(), createTheme(), extendTheme() | | @farming-labs/theme | Next.js theme presets, layout components, CSS presets | | @farming-labs/next | Next.js adapter — withDocs(), MDX processing, search API | | @farming-labs/svelte | SvelteKit adapter — server-side docs loader, markdown processing | | @farming-labs/svelte-theme | SvelteKit theme presets, DocsLayout, DocsContent components | | @farming-labs/astro | Astro adapter — server-side docs loader, markdown processing | | @farming-labs/astro-theme | Astro theme presets, DocsLayout, DocsContent components | | @farming-labs/nuxt | Nuxt 3 adapter — defineDocsHandler(), server-side docs loader, markdown processing | | @farming-labs/nuxt-theme | Nuxt theme presets, DocsLayout, DocsContent components | Quick Start The fastest way to get started is with the CLI: The CLI auto-detects your framework (Next.js, SvelteKit, Astro, or Nuxt), lets you pick a theme (fumadocs, darksharp, or pixel-border), and scaffolds everything you need — config, routes, CSS, sample pages — then starts the dev server. See the CLI reference for details, or set up manually with the Installation guide. Next Steps - Token Efficiency — Why this is the most AI-friendly docs framework - Configuration — Customize your theme, colors, typography, sidebar, and more - Themes — Browse available themes and learn how to create your own - Customization — Colors, typography, sidebar, AI chat, page actions - Ask AI — Add RAG-powered AI chat to your docs - API Reference — Complete reference for every config option --- ## CLI URL: https://farming-labs-docs.vercel.app/docs/cli Scaffold a docs project with one command CLI The @farming-labs/docs CLI scaffolds a documentation project in seconds. Usage If the CLI cannot auto-detect your framework (no next, @sveltejs/kit, astro, or nuxt in package.json), it will prompt you to choose one. Upgrade Upgrade all @farming-labs/ docs packages to the latest version. Run from your project root; the CLI auto-detects* your framework from package.json and upgrades the right packages. | Framework | Packages upgraded to @latest | | --------- | ------------------------------ | | Next.js | @farming-labs/docs, @farming-labs/theme, @farming-labs/next | | Nuxt | @farming-labs/docs, @farming-labs/nuxt, @farming-labs/nuxt-theme | | SvelteKit | @farming-labs/docs, @farming-labs/svelte, @farming-labs/svelte-theme | | Astro | @farming-labs/docs, @farming-labs/astro, @farming-labs/astro-theme | To specify the framework explicitly (e.g. in a monorepo or when auto-detect fails), use --framework: Valid values: next, nuxt, sveltekit, astro. Use --latest (default) to install the latest stable release, or --beta to install beta versions: Supported Frameworks | Framework | Detection | Status | | --------- | ------------------------------- | --------- | | Next.js | next in dependencies | Supported | | SvelteKit | @sveltejs/kit in dependencies | Supported | | Astro | astro in dependencies | Supported | | Nuxt | nuxt in dependencies | Supported | Available Themes Seven themes are available for Next.js, SvelteKit, Astro, and Nuxt: | Theme | Description | | -------------- | ---------------------------------------------------------- | | fumadocs | Clean, neutral docs theme (default) | | darksharp | All-black, sharp corners, no rounded edges | | pixel-border | Refined dark UI inspired by better-auth.com | | colorful | Fumadocs-style neutral theme with description support | | greentree | Emerald green accent, Inter font, Mintlify-inspired | | darkbold | Pure monochrome, Geist typography, clean minimalism | | shiny | Glossy, modern look with subtle shimmer effects | What it does 1. Detects Next.js via next in your package.json 2. Asks for a theme — one of 7 built-in themes (e.g. fumadocs, darksharp, pixel-border, colorful, greentree, darkbold, shiny) 3. Asks for the entry path — Default is docs (creates pages under app/docs/) 4. Asks about path aliases — Use @/ alias or relative paths for imports 5. Generates files: - docs.config.ts — Full config with your selected theme - next.config.ts — Wraps your existing config with withDocs() - app/global.css — Imports Tailwind and theme CSS - app/layout.tsx — Root layout with RootProvider - app/docs/layout.tsx — Docs layout - app/docs/page.mdx — Sample documentation page - app/docs/installation/page.mdx — Sample installation guide - app/docs/quickstart/page.mdx — Sample quickstart guide 6. Installs dependencies — @farming-labs/docs, @farming-labs/theme, @farming-labs/next 7. Starts the dev server — Opens your docs at http://localhost:3000/docs 1. Detects SvelteKit via @sveltejs/kit in your package.json 2. Asks for a theme — one of 7 built-in themes (e.g. fumadocs, darksharp, pixel-border, colorful, greentree, darkbold, shiny) 3. Asks for the entry path — Default is docs 4. Asks about path aliases — Use $lib/ alias or relative paths for imports 5. Generates files (does not touch svelte.config.js): - src/lib/docs.config.ts — Full config with your selected theme - src/lib/docs.server.ts — Server-side docs loader with import.meta.glob for production builds - src/routes/docs/+layout.svelte — Docs layout component - src/routes/docs/+layout.server.js — Layout data loader - src/routes/docs/[...slug]/+page.svelte — Dynamic page component - src/app.css — Theme CSS import - docs/page.md — Sample documentation page - docs/installation/page.md — Sample installation guide - docs/quickstart/page.md — Sample quickstart guide 6. Installs dependencies — @farming-labs/docs, @farming-labs/svelte, @farming-labs/svelte-theme 7. Starts the dev server — Opens your docs at http://localhost:5173/docs > Production note: The generated docs.server.ts uses import.meta.glob to bundle your markdown files at build time. This is required for serverless deployments (Vercel, Netlify, etc.) where the filesystem is not available at runtime. 1. Detects Astro via astro in your package.json 2. Asks for a theme — one of 7 built-in themes (e.g. fumadocs, darksharp, pixel-border, colorful, greentree, darkbold, shiny) 3. Asks for the entry path — Default is docs 4. Generates files: - src/lib/docs.config.ts — Full config with your selected theme - src/lib/docs.server.ts — Server-side docs loader with import.meta.glob for production builds - src/pages/{entry}/index.astro — Docs index page - src/pages/{entry}/[...slug].astro — Dynamic page component - src/pages/api/{entry}.ts — API route for search and AI - astro.config.mjs — Astro config with SSR enabled - docs/page.md — Sample documentation page - docs/installation/page.md — Sample installation guide - docs/quickstart/page.md — Sample quickstart guide 5. Installs dependencies — @farming-labs/docs, @farming-labs/astro, @farming-labs/astro-theme 6. Starts the dev server — Opens your docs at http://localhost:4321/docs > Production note: The generated docs.server.ts uses import.meta.glob to bundle your markdown files at build time. This is required for serverless deployments (Vercel, Netlify, etc.) where the filesystem is not available at runtime. 1. Detects Nuxt via nuxt in your package.json 2. Asks for a theme — one of 7 built-in themes (e.g. fumadocs, darksharp, pixel-border, colorful, greentree, darkbold, shiny) 3. Asks for the entry path — Default is docs 4. Generates files: - docs.config.ts — Full config with your selected theme - nuxt.config.ts — Nuxt config with theme CSS and server assets - server/api/docs.ts — API route for docs data, search, and AI - pages/docs/[...slug].vue — Dynamic page component - docs/page.md — Sample documentation page - docs/installation/page.md — Sample installation guide - docs/quickstart/page.md — Sample quickstart guide 5. Installs dependencies — @farming-labs/docs, @farming-labs/nuxt, @farming-labs/nuxt-theme 6. Starts the dev server — Opens your docs at http://localhost:3000/docs Example Output Flags | Flag | Description | | ----------------------- | --------------------------------------------------------------------------- | | --template | Bootstrap a project: next, nuxt, sveltekit, or astro. Use with --name. | | --name | Project folder name when using --template; prompt if omitted (e.g. my-docs) | | --theme | Skip theme prompt (e.g. --theme darksharp, --theme greentree) | | --entry | Skip entry path prompt (e.g. --entry docs) | Starting from scratch? Use --template with --name . The CLI bootstraps a project with the given name, installs dependencies, and then you run cd && pnpm run dev to start. Manual Code Here is every file the CLI generates, ready to copy-paste if you prefer manual setup. For each framework, add your theme's CSS to the global stylesheet (or config) shown below. The import must match the theme you use in docs.config (e.g. default, greentree, darksharp). Without it, docs pages will lack the correct styling. docs.config.tsx next.config.ts app/global.css — add your theme's CSS here so docs styling applies. app/layout.tsx app/docs/layout.tsx app/docs/page.mdx (sample page) > If you chose darksharp or pixel-border, the CSS import line will differ: > - Darksharp: @import "@farming-labs/theme/darksharp/css"; > - Pixel Border: @import "@farming-labs/theme/pixel-border/css"; src/lib/docs.config.ts src/lib/docs.server.ts src/routes/docs/+layout.svelte src/routes/docs/+layout.server.js src/routes/docs/[...slug]/+page.svelte src/routes/api/docs/+server.js (search & AI) src/app.css — add your theme's CSS here so docs styling applies. docs/page.md (sample page) > If you chose darksharp or pixel-border, swap the theme factory and CSS: > - Darksharp: import { darksharp } from "@farming-labs/svelte-theme" + @import "@farming-labs/svelte-theme/darksharp/css"; > - Pixel Border: import { pixelBorder } from "@farming-labs/svelte-theme" + @import "@farming-labs/svelte-theme/pixel-border/css"; src/lib/docs.config.ts src/lib/docs.server.ts src/pages/docs/index.astro and src/pages/docs/[...slug].astro — import your theme's CSS in each (e.g. @farming-labs/astro-theme/css for default; use greentree/css etc. for other themes). src/pages/api/docs.ts (search & AI) astro.config.mjs docs/page.md (sample page) > If you chose darksharp or pixel-border, swap the theme factory and CSS: > - Darksharp: import { darksharp } from "@farming-labs/astro-theme" + @farming-labs/astro-theme/darksharp/css > - Pixel Border: import { pixelBorder } from "@farming-labs/astro-theme" + @farming-labs/astro-theme/pixel-border/css docs.config.ts nuxt.config.ts — add your theme's CSS in the css array so docs styling applies. server/api/docs.ts (search & AI) pages/docs/[...slug].vue docs/page.md (sample page) > If you chose darksharp or pixel-border, swap the theme factory and CSS: > - Darksharp: import { darksharp } from "@farming-labs/nuxt-theme" + @farming-labs/nuxt-theme/darksharp/css > - Pixel Border: import { pixelBorder } from "@farming-labs/nuxt-theme" + @farming-labs/nuxt-theme/pixel-border/css Project Structure After running init, your project will look like this: --- ## Configuration URL: https://farming-labs-docs.vercel.app/docs/configuration Everything lives in docs.config.ts Configuration All configuration lives in a single docs.config.ts file. The config file lives at the project root as docs.config.tsx: The config file lives at src/lib/docs.config.ts: > SvelteKit, Astro, and Nuxt require contentDir (path to your markdown files) and nav (sidebar title/URL) since routing is handled differently from Next.js. The config file lives at src/lib/docs.config.ts: The config file lives at the project root as docs.config.ts: Config Options | Option | Type | Default | Description | | -------------- | ------------------------------ | --------------- | -------------------------------------------------- | | entry | string | "docs" | The docs URL path prefix (e.g. "docs" → /docs) | | contentDir | string | same as entry | Path to content files (SvelteKit, Astro, Nuxt) | | staticExport | boolean | false | Set true for full static builds (see Static export) | | theme | DocsTheme | — | Theme preset from a theme factory | | nav | { title, url } | — | Sidebar title and base URL | | github | string \| GithubConfig | — | GitHub repo for "Edit on GitHub" links | | themeToggle | boolean \| ThemeToggleConfig | true | Light/dark mode toggle | | breadcrumb | boolean \| BreadcrumbConfig | true | Breadcrumb navigation | | sidebar | boolean \| SidebarConfig | true | Sidebar visibility and style | | icons | Record | — | Icon registry for frontmatter icon fields | | components | Record | — | Custom MDX components | | onCopyClick | (data: CodeBlockCopyData) => void | — | Callback when the user clicks the copy button on a code block | | pageActions | PageActionsConfig | — | Copy Markdown, Open in LLM buttons | | ai | AIConfig | — | RAG-powered AI chat | | metadata | DocsMetadata | — | SEO metadata template | | og | OGConfig | — | Dynamic Open Graph images (see API Reference) | Static export For fully static builds (e.g. Cloudflare Pages, static hosting with no server), set staticExport: true in your config. This: - Next.js: With output: "export" in next.config, the /api/docs route is not generated. The layout hides Cmd+K search and AI chat. - SvelteKit / Astro / Nuxt: The layout hides the search trigger and floating AI when staticExport is true. Omit or don’t deploy the docs API route so no server is required. Use this when you deploy to a static host and don’t run a server. Search and AI require a server; with staticExport: true they are hidden so the site works without one. Theme Toggle Controls the light/dark mode switcher. Works on Next.js, SvelteKit, Astro, and Nuxt. | Property | Type | Default | Description | | --------- | ------------------------------------- | -------------- | ---------------------------------- | | enabled | boolean | true | Show/hide the theme toggle | | default | "light" \| "dark" \| "system" | "system" | Forced theme when toggle is hidden | | mode | "light-dark" \| "light-dark-system" | "light-dark" | Toggle mode | GitHub / Edit on GitHub Enables "Edit on GitHub" links on each docs page footer. The link appears automatically when both url and directory are set. | Property | Type | Default | Description | | ----------- | -------- | -------- | ---------------------------------- | | url | string | — | Repository URL | | branch | string | "main" | Branch name | | directory | string | — | Subdirectory for the content files | Breadcrumb Controls the breadcrumb navigation above page content. Theme Configuration Pass options to your theme preset to customize colors, typography, layout, and more: See Colors, Typography, and Sidebar for full details. Navigation The nav option controls the sidebar header: In Next.js, title can also be a React element: Icons Register icons in the config and reference them in frontmatter: SvelteKit uses a built-in icon map. Add icon to your page frontmatter: Built-in icons: book, terminal, rocket, settings, shield, puzzle, zap, database, key, mail, file, folder, link, lightbulb, code, users, globe, lock. Astro uses a built-in icon map. Add icon to your page frontmatter: Built-in icons: book, terminal, rocket, settings, shield, puzzle, zap, database, key, mail, file, folder, link, lightbulb, code, users, globe, lock. Nuxt uses a built-in icon map. Add icon to your page frontmatter: Built-in icons: book, terminal, rocket, settings, shield, puzzle, zap, database, key, mail, file, folder, link, lightbulb, code, users, globe, lock. Code block copy callback Run a callback when the user clicks the copy button on a code block (in addition to the default copy-to-clipboard). Useful for analytics or logging. Next.js: Set onCopyClick in defineDocs(); it is passed through to the MDX components. SvelteKit, Astro, Nuxt: Config is serialized at build time so you cannot pass a function. Use one of these: 1. Global callback — In a client-side script (e.g. in your layout), set window.fdOnCopyClick to your function. It will be called with CodeBlockCopyData after each copy. 2. Custom event — Listen for the fd:code-block-copy event on document or window; event.detail is the same { title?, content, url, language? } object. The callback receives title (if the code block has a title), content (raw code), url (current page URL), and language (syntax hint) when available. Page Actions Enable "Copy as Markdown" and "Open in LLM" buttons: See the full Page Actions reference for all options. Ask AI Add a RAG-powered AI chat that lets users ask questions about your docs: The API key is read from process.env.OPENAIAPIKEY automatically. Pass the API key through docs.server.ts (SvelteKit requires server-only env access): Pass the API key through docs.server.ts (Astro requires server-only env access): Pass the API key through the server handler (Nuxt requires server-only env access): See the full Ask AI reference for all options including custom providers, labels, system prompts, and more. Full Example --- ## Customization URL: https://farming-labs-docs.vercel.app/docs/customization Colors, typography, sidebar, components, OG images, AI chat, and page actions Customization Everything is customizable from docs.config.tsx. No CSS files to edit, no layout files to create. What You Can Customize - Colors — Primary, accent, background, border, and more - Typography — Font families, heading sizes, weights, spacing - Sidebar — Title, icons, collapsible groups, style - Components — Override built-in or add custom MDX components - OG Images — Dynamic or static Open Graph images; what context your image generator receives; how the docs website does it - Ask AI — RAG-powered AI chat with configurable LLM, floating/search modes, and more - Page Actions — "Copy Markdown" and "Open in LLM" buttons on doc pages - llms.txt — Auto-generate llms.txt and llms-full.txt for LLM-friendly documentation All customization happens through the theme and top-level config options in docs.config.tsx. --- ## Ask AI URL: https://farming-labs-docs.vercel.app/docs/customization/ai-chat Add a RAG-powered AI chat to your documentation Ask AI Add a built-in AI chat that lets users ask questions about your documentation. The AI searches relevant pages, builds context, and streams a response from any OpenAI-compatible LLM. Quick Start That's it. The AI reads your OPENAIAPIKEY environment variable and uses gpt-4o-mini by default. Add OPENAIAPIKEY to your .env file: The key is automatically read from process.env.OPENAIAPIKEY. Add OPENAIAPIKEY to your .env file: Pass it through docs.server.ts (SvelteKit requires server-only env access): Add OPENAIAPIKEY to your .env file: Pass it through docs.server.ts: Add OPENAIAPIKEY to your .env file: Nuxt automatically reads environment variables via Nitro's runtime config. The defineDocsHandler reads process.env.OPENAIAPIKEY on the server. Configuration Reference All options go inside the ai object in docs.config.ts: enabled Whether to enable AI chat functionality. | Type | Default | | --------- | ------- | | boolean | false | mode How the AI chat UI is presented. | Type | Default | | ------------------------ | ---------- | | "search" \| "floating" | "search" | - "search" — AI tab integrated into the Cmd+K search dialog. Users switch between "Search" and "AI" tabs. - "floating" — A floating chat widget with a button on screen. Opens as a panel, modal, or full-screen overlay. position Position of the floating chat button on screen. Only used when mode is "floating". | Type | Default | | ---------------------------------------------------- | ---------------- | | "bottom-right" \| "bottom-left" \| "bottom-center" | "bottom-right" | floatingStyle Visual style of the floating chat when opened. Only used when mode is "floating". | Type | Default | | ------------------------------------------------- | --------- | | "panel" \| "modal" \| "popover" \| "full-modal" | "panel" | - "panel" — A tall panel that slides up from the button position. No backdrop overlay. - "modal" — A centered modal dialog with a backdrop overlay, similar to the Cmd+K search dialog. - "popover" — A compact popover near the button. Suitable for quick questions. - "full-modal" — A full-screen immersive overlay. Messages scroll in the center, input is pinned at the bottom, suggested questions appear as horizontal pills. model The LLM model configuration. Can be a simple string (single model) or an object with multiple selectable models. Simple — single model: | Type | Default | | -------- | --------------- | | string | "gpt-4o-mini" | Advanced — multiple models with UI dropdown: | Type | Default | | -------- | ------- | | object | — | Each model entry has: - id — The model identifier sent to the LLM API (e.g. "gpt-4o-mini") - label — Display name shown in the UI dropdown (e.g. "GPT-4o mini (fast)") - provider — (optional) Key matching a named provider in the providers config. If omitted, uses the default baseUrl and apiKey. When model is an object with a models array, a model selector dropdown appears in the AI chat interface so users can pick which model to use. providers Named provider configurations. Each provider has its own baseUrl and apiKey, allowing models from different providers to coexist in a single config. | Type | Default | | -------- | ------- | | object | — | When a user selects a model in the dropdown, the backend automatically uses that model's provider to resolve the correct baseUrl and apiKey. All providers must be OpenAI Chat Completions API compatible (OpenAI, Groq, Together, Fireworks, OpenRouter, Ollama, any vLLM deployment). baseUrl Default base URL for an OpenAI-compatible API endpoint. Used when no per-model provider is configured. | Type | Default | | -------- | ----------------------------- | | string | "https://api.openai.com/v1" | apiKey Default API key for the LLM provider. Used when no per-model provider is configured. Falls back to process.env.OPENAIAPIKEY if not set. | Type | Default | | -------- | ---------------------------- | | string | process.env.OPENAIAPIKEY | Warning: Never hardcode API keys. Always use environment variables. systemPrompt Custom system prompt prepended to the AI conversation. Documentation context is automatically appended after this prompt. | Type | Default | | -------- | ------------------------------------------------ | | string | "You are a helpful documentation assistant..." | maxResults Maximum number of search results to include as context for the AI. More results = more context but higher token usage. | Type | Default | | -------- | ------- | | number | 5 | suggestedQuestions Pre-filled suggested questions shown in the AI chat when the conversation is empty. Clicking one fills the input and submits automatically. | Type | Default | | ---------- | ------- | | string[] | [] | aiLabel Display name for the AI assistant in the chat UI. Shown as the message label and header title. | Type | Default | | -------- | ------- | | string | "AI" | packageName The npm package name used in code examples. The AI will use this in import snippets instead of generic placeholders. | Type | Default | | -------- | ------- | | string | — | docsUrl The public URL of your documentation site. The AI will use this for absolute links instead of relative paths. | Type | Default | | -------- | ------- | | string | — | loader Loading indicator variant shown while the AI generates a response. | Type | Default | | -------- | ---------------- | | string | "shimmer-dots" | Available variants: "shimmer-dots", "circular", "dots", "typing", "wave", "bars", "pulse", "pulse-dot", "terminal", "text-blink", "text-shimmer", "loading-dots". loadingComponent Custom React component that completely overrides the built-in loader variant. Receives { name } (the aiLabel value). Only works in Next.js — for other frameworks, use the loader option. | Type | Default | | ------------------------------------------ | ------- | | (props: { name: string }) => ReactNode | — | triggerComponent Custom trigger button for the floating chat. Replaces the default sparkles button. Only used when mode is "floating". Each framework accepts its native component format — pass it as a prop on DocsLayout (or a slot in Astro). | Type | Default | | ----------- | ------------------------ | | Component | Built-in sparkles button | Pass a React component via docs.config.tsx: Import a Svelte component and pass it as a prop on DocsLayout: Use the trigger-component slot on DocsLayout: Import a Vue component and pass it as a prop on DocsLayout: Full Example — Single Provider Full Example — Multiple Providers Users see a model dropdown in the AI chat interface. When they pick a model, the backend automatically routes the request to the correct provider's API with the right credentials. Using a Different LLM Provider Single provider (simple) Use any OpenAI-compatible API by setting baseUrl and model: Multiple providers Use the providers map to configure multiple APIs, then reference them from each model entry: Compatible providers: OpenAI, Groq, Together AI, Fireworks, OpenRouter, Azure OpenAI, Ollama (local), any vLLM deployment — anything that speaks the OpenAI Chat Completions API format. --- ## Colors URL: https://farming-labs-docs.vercel.app/docs/customization/colors Override any color token from config Colors Override any color token directly from your config. Colors are mapped to --color-fd-* CSS variables at runtime. Setting Colors Available Tokens | Token | CSS Variable | Description | | ------------------- | ------------------------------- | --------------------------- | | primary | --color-fd-primary | Primary brand color | | primaryForeground | --color-fd-primary-foreground | Text on primary backgrounds | | background | --color-fd-background | Page background | | foreground | --color-fd-foreground | Default text color | | muted | --color-fd-muted | Muted background | | mutedForeground | --color-fd-muted-foreground | Muted text | | border | --color-fd-border | Border color | | card | --color-fd-card | Card background | | accent | --color-fd-accent | Accent background | | accentForeground | --color-fd-accent-foreground | Text on accent | | secondary | --color-fd-secondary | Secondary background | | ring | --color-fd-ring | Focus ring color | How It Works Only colors you explicitly set are emitted as inline CSS variables. Theme preset defaults stay in the CSS file — your overrides don't break light/dark mode handling. Color Formats Any valid CSS color value works: --- ## Components URL: https://farming-labs-docs.vercel.app/docs/customization/components Override built-in or add custom MDX components Components Pass custom React components that become available in all MDX files — no imports needed. How It Works When you register components in docs.config.tsx, they're merged into the MDX component map via getMDXComponents(). The merge order is: 1. Built-in components — headings, code blocks, callouts, Tab, Tabs, etc. 2. Your components — from docs.config.tsx (overrides built-ins if names match) This means you can both add new components and override existing ones. Creating a Custom Component 1. Create the component 2. Register in config 3. Use in any MDX file No import needed — just use it directly: Overriding Built-in Components You can replace any built-in MDX component by registering one with the same name. Your component will take precedence. Available built-in components The following components are available by default (from fumadocs-ui): - h1, h2, h3, h4, h5, h6 — heading elements - p, a, ul, ol, li — text and list elements - table, thead, tbody, tr, th, td — table elements - pre, code — code blocks and inline code - img — images - blockquote — blockquotes - hr — horizontal rules - Tab, Tabs — tabbed content - Callout — callout/admonition boxes Example: Override the a tag Now every link in your MDX files will use CustomLink — external links open in a new tab with an arrow indicator. Example: Override blockquote Example: Override pre (code blocks) Multiple Components Register as many components as you need: Then use them all across your MDX without imports: Component Props Components receive their props as defined in your implementation. The only requirement is that they must be valid React components (function or class). For built-in overrides, your component should accept the same props as the original element (e.g., React.AnchorHTMLAttributes for a, React.HTMLAttributes for pre). For custom components, define whatever props interface you need. --- ## llms.txt URL: https://farming-labs-docs.vercel.app/docs/customization/llms-txt Auto-generate llms.txt and llms-full.txt for LLM-friendly documentation llms.txt Serve llms.txt content through your existing docs API — no extra route files needed. Just enable it in your config. What is llms.txt? llms.txt is a standard for making website content accessible to LLMs. It's served via query params on your existing /api/docs endpoint: - /api/docs?format=llms — A concise markdown listing of all pages with titles, URLs, and descriptions - /api/docs?format=llms-full — The full stripped content of every page, ready for LLM consumption Quick Start That's it. The existing API handler serves the content automatically — no extra route files needed. Configuration Reference All options go inside the llmsTxt object in docs.config.ts: llmsTxt.enabled Enable or disable llms.txt generation. | Type | Default | | --------- | ------- | | boolean | false | llmsTxt.baseUrl Base URL prepended to all page links in the generated files. | Type | Default | | -------- | ------- | | string | "" | llmsTxt.siteTitle Title shown at the top of the generated files. Falls back to nav.title if not set. | Type | Default | | -------- | --------------- | | string | nav.title | llmsTxt.siteDescription Description shown below the title. | Type | Default | | -------- | ----------- | | string | undefined | How It Works No extra route files are needed. The existing API handler (/api/docs on Next.js, or your framework's equivalent) serves the llms.txt content when you pass the format query parameter: - GET /api/docs?format=llms — concise page listing - GET /api/docs?format=llms-full — full page content This works identically across Next.js, SvelteKit, Astro, and Nuxt — just enable llmsTxt in your config and the existing createDocsAPI() / createDocsServer() handler takes care of the rest. Output Example /api/docs?format=llms /api/docs?format=llms-full Footer Links When enabled, llms.txt and llms-full.txt links automatically appear in the page footer next to "Edit on GitHub", pointing to /api/docs?format=llms and /api/docs?format=llms-full respectively. Full Example --- ## OG Images URL: https://farming-labs-docs.vercel.app/docs/customization/og-images Dynamic and static Open Graph images for docs — how they work, what context is passed, and how the docs website generates them OG Images Open Graph (OG) images are the preview images shown when your docs pages are shared on social platforms, Slack, or messaging apps. This guide explains how the framework supports dynamic (generated per page) and static (per-page image file) OG images, what data your image generator receives, and how the docs website implements dynamic OG. Overview: static vs dynamic One design for all pages; title and description change per page. You implement an API route. The framework calls it with the page’s title and description (from frontmatter) as query params and uses the returned image URL for og:image and twitter:image. Custom image per page (e.g. diagrams, screenshots). Set openGraph and/or twitter (or the shorthand ogImage) in that page’s frontmatter. The framework uses those values instead of calling the dynamic endpoint. You can mix both: use a dynamic endpoint by default and override with static images on specific pages via frontmatter. How dynamic OG works 1. You configure an OG endpoint in docs.config.tsx: - og: { enabled: true, type: "dynamic", endpoint: "/api/og" } 2. For each docs page, the framework builds a single URL that includes the page’s context: - Next.js (MDX): A remark plugin injects that URL into the page’s exported metadata (from frontmatter). The URL is your endpoint plus query params. - Query params the framework adds: - title — the page’s title from frontmatter (required). - description — the page’s description from frontmatter (optional). 3. Your API route receives a GET request with those query params and returns a 1200×630 image (e.g. PNG). 4. The framework sets that URL as og:image and twitter:image in the page metadata, so crawlers and social platforms fetch the image when the page is shared. So your image generator gets full context: the same title and description that appear in the doc and in meta tags. You can render them (and any other logic) inside your image. What context your image generator receives When the framework calls your dynamic OG endpoint, it passes: | Query param | Source | Example value | | ------------- | ----------------- | -------------------- | | title | Page frontmatter title | Introduction or OG Images | | description | Page frontmatter description | Dynamic and static Open Graph images for docs. | The URL looks like: Your route reads searchParams.get("title") and searchParams.get("description") and uses them when rendering the image (e.g. in ImageResponse). That’s the full context the framework provides; you can add more query params in your own links if needed. Example: how the docs website uses dynamic OG The @farming-labs/docs website which uses Nextjs uses a dynamic OG endpoint so every docs page gets a unique preview image with that page’s title and description. 1. Config (docs.config.tsx) No other OG config is required; the framework builds the URL for each page and injects it into metadata. 2. API route (app/api/og/route.ts) The route receives title and description from the query string and returns a 1200×630 image using Next.js ImageResponse: So the image generator has full context: the same title and description that come from the MDX frontmatter. The live site loads Inter and JetBrains Mono for typography and uses the same layout with diagonal pattern and borders; the only variables are title and description. 3. What each page gets - Introduction (/docs) → /api/og?title=Introduction&description=... - OG Images (/docs/customization/og-images) → /api/og?title=OG+Images&description=Dynamic+and+static+... - API Reference (/docs/reference) → /api/og?title=API+Reference&description=... Each URL is set as that page’s og:image and twitter:image, so shares show the correct title and description on the card. Using static OG for specific pages To use a static image for a single page (e.g. a pre-made graphic or screenshot), set openGraph and twitter in that page’s frontmatter. The framework will use those instead of calling the dynamic endpoint for that page. Shorthand: you can set only ogImage: "/og/some-page.png" and the framework will use it for both Open Graph and Twitter unless you override with full openGraph / twitter. See Page Frontmatter for all options. Configuration reference | Option | Type | Description | | ------------- | -------- | ----------- | | og.enabled | boolean| Turn OG/twitter images on or off. | | og.type | "static" \| "dynamic" | Use a fixed image or a dynamic endpoint. | | og.endpoint | string| Path to your OG API route (e.g. "/api/og"). Required for dynamic. | | og.defaultImage | string | Fallback OG image URL when no page-specific OG is set. | Full details: OGConfig in the API reference. Testing your OG image 1. Start your dev server (e.g. pnpm dev). 2. Open the endpoint with sample params in the browser: - http://localhost:3000/api/og?title=Test+Page&description=My+description 3. Confirm the image shows the right title and description. 4. After code changes, do a hard refresh (e.g. Cmd+Shift+R) or use a cache-busting query (e.g. &_=1) so you see the latest image. Summary - Dynamic OG gives every docs page a generated preview: the framework calls your endpoint with title and description from frontmatter, and you return a 1200×630 image. The docs website uses this with a single /api/og route. - Static OG lets you set a specific image per page via frontmatter (openGraph, twitter, or ogImage), which overrides the dynamic endpoint for that page. - Your image generator receives the full context it needs: the page’s title and description as query parameters, so you can render them (and anything else you derive from them) in your image. --- ## Page Actions URL: https://farming-labs-docs.vercel.app/docs/customization/page-actions Add "Open in LLM" and "Copy Markdown" buttons to your doc pages Page Actions Page actions are buttons rendered above or below the page title. They let users interact with page content — copy it as Markdown, or open it in an LLM provider like ChatGPT or Claude. Quick Start This adds two buttons: Copy Markdown and an Open in... dropdown. Configuration Reference All options go inside the pageActions object in docs.config.ts: pageActions.position Where to render the page action buttons relative to the page title. | Type | Default | | -------------------------------- | --------------- | | "above-title" \| "below-title" | "below-title" | Copy Markdown pageActions.copyMarkdown Whether to show the "Copy Markdown" button. Copies the current page's content as Markdown to the clipboard. | Type | Default | | --------------------------------- | ------- | | boolean \| { enabled: boolean } | false | Open in LLM The Open in... dropdown lets users send the current page to an LLM or tool. Each provider gets a link that includes the page URL as context. pageActions.openDocs Enable the "Open in..." dropdown. Can be a boolean or an object with additional configuration. | Type | Default | | --------------------------- | ------- | | boolean \| OpenDocsConfig | false | When set to true, a sensible default list of providers is used. pageActions.openDocs.enabled Whether to show the "Open in..." dropdown. | Type | Default | | --------- | ------- | | boolean | false | pageActions.openDocs.providers Custom list of LLM / tool providers to show in the dropdown. Overrides the default list. | Type | Default | | -------------------- | ----------------- | | OpenDocsProvider[] | Built-in defaults | Each provider has the following shape: Provider URL Templates The urlTemplate string supports these placeholders: | Placeholder | Replaced with | | ------------- | ----------------------------------------------------------------------------- | | {url} | The current page URL (e.g. https://docs.example.com/docs/installation) | | {mdxUrl} | The .mdx variant of the page URL (useful for raw source) | | {githubUrl} | GitHub edit URL for the current page (same as "Edit on GitHub"). Requires github in config. Use urlTemplate: "{githubUrl}" so "Open in GitHub" opens the file on GitHub. | Custom Providers Example Cursor deeplink: The example uses the web format (https://cursor.com/link/prompt?text=...). To open the Cursor app directly instead, use the app scheme: cursor://anysphere.cursor-deeplink/prompt?text=Read+this+documentation:+{url}. With Icons (Next.js) In Next.js, you can pass React elements for icons: Full Example --- ## Sidebar URL: https://farming-labs-docs.vercel.app/docs/customization/sidebar Title, icons, collapsible groups, and styling Sidebar The sidebar is auto-generated from your file structure. Customize its appearance through config. Custom Title The sidebar title supports strings or React components: Icons Add icons to sidebar items via frontmatter: Register icons in your config: Collapsible Groups Nested directories automatically become collapsible groups. A directory with its own page.mdx becomes a folder with an index page: Flat Mode Render all sidebar items without collapsible sections (Mintlify-style): Sidebar Header & Footer Add custom content above and below the navigation items using banner and footer: The banner renders above the navigation items and footer renders below them, both inheriting the theme's sidebar styling automatically. For non-React frameworks, use named slots: Pass sidebarHeader and sidebarFooter snippets: Use sidebar-header and sidebar-footer named slots: Use #sidebar-header and #sidebar-footer slots: Custom Sidebar Component Replace the entire sidebar navigation with your own component. The component receives the full page tree with all parent-child relationships. Pass a render function via sidebar.component in your config: Your component receives the full tree structure: Use the sidebar snippet on `. It receives tree and isActive: Use the sidebar named slot: Use the #sidebar scoped slot: Tree Structure The tree prop has this shape: All types are exported from @farming-labs/docs for full type safety. Sidebar Style Breadcrumbs Enable breadcrumb navigation: Shows Parent / Current Page` with the parent being clickable. --- ## Typography URL: https://farming-labs-docs.vercel.app/docs/customization/typography Fonts, heading sizes, weights, and spacing Typography Control fonts, heading sizes, weights, line heights, and letter spacing — all from config. Font Families Heading Styles Each heading level can be individually configured: Font Style Properties | Property | Type | Description | | --------------- | -------- | --------------------------------- | | size | string | CSS font-size (e.g. "2rem") | | weight | number | Font weight (e.g. 700) | | lineHeight | string | Line height (e.g. "1.2") | | letterSpacing | string | Letter spacing (e.g. "-0.02em") | Using Google Fonts Load fonts in your app/layout.tsx and reference them via CSS variables: Then reference them in your typography config: --- ## Installation URL: https://farming-labs-docs.vercel.app/docs/installation Get up and running in minutes Installation Option A: CLI (Recommended) Starting from scratch? Use --template with --name to bootstrap a new docs project (Next.js, Nuxt, SvelteKit, or Astro). No prompts — the CLI creates the project folder and runs install. See the --template section below. Adding docs to an existing app? Run the init command inside your Next.js, SvelteKit, Astro, or Nuxt project: The CLI will: 1. Detect your framework (Next.js, SvelteKit, Astro, or Nuxt) 2. Ask you to pick a theme 3. Ask for the docs entry path (default: docs) 4. Generate config, layout, CSS, and sample pages 5. Install all required dependencies 6. Start the dev server and give you a live URL To upgrade all docs packages to the latest later, run from your project root: npx @farming-labs/docs@latest upgrade (framework is auto-detected). See CLI — Upgrade for options. Starting from scratch or want a full example? Use --template with --name to bootstrap a ready-to-run docs app. The CLI creates the project folder, bootstraps it with the chosen framework, and runs install: Replace my-docs with your project name. Then run cd my-docs && pnpm run dev (or your package manager’s dev command) to start the dev server. Option B: Manual Setup For each framework below, add your theme's CSS to your global stylesheet (e.g. app/global.css, src/app.css, or nuxt.config). The import path must match the theme you use in docs.config — e.g. default, greentree, darksharp. Without it, docs pages will lack the correct styling. ### 1. Install packages ### 2. Create docs.config.tsx ### 3. Create next.config.ts ### 4. Set up RootProvider in app/layout.tsx Wrap your app with RootProvider from @farming-labs/theme. This enables search, theme switching, and AI chat across all pages. > RootProvider automatically configures the search API endpoint (/api/docs) and handles theme persistence. The suppressHydrationWarning on ` prevents React warnings from the theme class injection. ### 5. Import theme CSS in app/global.css Add your theme's CSS to your global stylesheet so docs styling applies. Use the import that matches the theme in your config (e.g. default below; for greentree use @farming-labs/theme/greentree/css). ### 6. Write your first doc Create an MDX file under app/docs/: Each page uses frontmatter for metadata: That's it — the docs layout (app/docs/layout.tsx) is auto-generated by withDocs(). The framework handles routing, MDX compilation, and metadata from your config. > See CLI for all generated files including the full app/layout.tsx and app/docs/layout.tsx, or check Configuration for all available options. ### 1. Install packages ### 2. Create src/lib/docs.config.ts ### 3. Create src/lib/docs.server.ts ### 4. Create route files src/routes/docs/+layout.svelte: src/routes/docs/+layout.server.js: src/routes/docs/[...slug]/+page.svelte: src/routes/api/docs/+server.js (for search and AI): > Production note: The docs.server.ts file uses import.meta.glob to bundle your markdown files at build time. This is required for serverless deployments (Vercel, Netlify, etc.) where the filesystem is not available at runtime. ### 5. Import theme CSS in src/app.css Add your theme's CSS to your global stylesheet so docs styling applies. Use the import that matches the theme in your config (e.g. fumadocs below; for greentree use @farming-labs/svelte-theme/greentree/css). ### 6. Write your first doc Create Markdown files under docs/: Each page uses frontmatter for metadata: ### 1. Install packages ### 2. Create src/lib/docs.config.ts ### 3. Create src/lib/docs.server.ts ### 4. Create page routes Import your theme's CSS in each docs page (or in a global CSS file and import that). The example below uses @farming-labs/astro-theme/css (default); for other themes use e.g. @farming-labs/astro-theme/greentree/css. src/pages/docs/index.astro and src/pages/docs/[...slug].astro: ### 5. Create API route src/pages/api/docs.ts: ### 6. Astro config Enable SSR in astro.config.mjs: ### 7. Write your first doc Create Markdown files under docs/: Each page uses frontmatter for metadata: ### 1. Install packages ### 2. Create docs.config.ts ### 3. Configure nuxt.config.ts Add your theme's CSS via the css array so docs styling applies. Use the path that matches the theme in your config (e.g. fumadocs below; for greentree use @farming-labs/nuxt-theme/greentree/css). ### 4. Create server/api/docs.ts ### 5. Create pages/docs/[...slug].vue > Nuxt uses Nitro's server assets to load markdown files at runtime. The serverAssets config in nuxt.config.ts tells Nitro where your docs directory is. ### 6. Write your first doc Create Markdown files under docs/`: Each page uses frontmatter for metadata: --- ## API Reference URL: https://farming-labs-docs.vercel.app/docs/reference Complete reference for all configuration options 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. DocsConfig Top-level configuration object passed to defineDocs(). | Property | Type | Default | Description | | -------------- | ----------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------ | | entry | string | required | URL path prefix for docs (e.g. "docs" → /docs) | | contentDir | string | same as entry | Path to content files. SvelteKit, Astro, and Nuxt only — Next.js uses app/{entry}/ | | staticExport | boolean | false | Set true for full static builds; hides search and AI (see Configuration) | | theme | DocsTheme | — | Theme preset from a factory (fumadocs(), darksharp(), pixelBorder(), etc.) | | github | string \| GithubConfig | — | GitHub repo config for "Edit on GitHub" links | | nav | DocsNav | — | Sidebar header title and URL | | themeToggle | boolean \| ThemeToggleConfig | true | Light/dark mode toggle | | breadcrumb | boolean \| BreadcrumbConfig | true | Breadcrumb navigation | | sidebar | boolean \| SidebarConfig | true | Sidebar visibility and customization | | icons | Record | — | Icon registry for frontmatter icon fields | | components | Record | — | Custom MDX component overrides | | onCopyClick | (data: CodeBlockCopyData) => void | — | Callback when the user clicks the copy button on a code block (runs in addition to copy) | | pageActions | PageActionsConfig | — | "Copy Markdown" and "Open in LLM" buttons | | ai | AIConfig | — | RAG-powered AI chat | | ordering | "alphabetical" \| "numeric" \| OrderingItem[] | "alphabetical" | Sidebar page ordering strategy | | metadata | DocsMetadata | — | SEO metadata | | og | OGConfig | — | Open Graph image config | 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. "numeric" Pages are sorted by the order field in frontmatter. Lower numbers appear first. Pages without order are sorted alphabetically after ordered pages. Then in your page frontmatter: Slug-based (OrderingItem[]) Pass an array of { slug, children? } objects for explicit control over page order, including nested pages. OrderingItem | Property | Type | Description | | ---------- | ---------------- | --------------------------------------------- | | slug | string | Folder name at this level (not the full path) | | children | OrderingItem[] | Ordering for child pages within this folder | Pages not listed in the array appear alphabetically after the listed ones. DocsNav Sidebar header configuration. | Property | Type | Default | Description | | -------- | --------------------- | ------------ | --------------------------------------------------------- | | title | string \| ReactNode | "Docs" | Sidebar header title. React elements supported in Next.js | | url | string | "/{entry}" | URL the title links to | GithubConfig GitHub repository configuration. Enables "Edit on GitHub" links in page footers. | Property | Type | Default | Description | | ----------- | -------- | ------------ | -------------------------------------------------------- | | url | string | required | Repository URL (e.g. "https://github.com/my-org/repo") | | branch | string | "main" | Branch name | | directory | string | — | Content subdirectory for monorepos | 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 vs SvelteKit/Astro/Nuxt). CodeBlockCopyData Argument passed to onCopyClick(data: CodeBlockCopyData). | Property | Type | Description | | ---------- | -------- | --------------------------------------------------------------------------- | | title | string \| undefined | Code block title (e.g. from fenced code meta), if present | | content | string | Raw code content (what was copied) | | url | string | Current page URL at the time of copy | | language | string \| undefined | Language/syntax hint (e.g. "tsx", "bash"), if present | ThemeToggleConfig Light/dark mode toggle in the sidebar. | Property | Type | Default | Description | | --------- | ------------------------------------- | -------------- | ---------------------------------- | | enabled | boolean | true | Show or hide the toggle | | default | "light" \| "dark" \| "system" | "system" | Forced theme when enabled: false | | mode | "light-dark" \| "light-dark-system" | "light-dark" | Toggle behavior | BreadcrumbConfig Breadcrumb navigation above page content. | Property | Type | Default | Description | | ----------- | ----------- | ------- | ------------------------------------------ | | enabled | boolean | true | Show or hide breadcrumbs | | component | Component | — | Custom breadcrumb component (Next.js only) | SidebarConfig Sidebar visibility and customization. See Sidebar for the full guide including custom sidebar components. | Property | Type | Default | Description | | ------------- | ------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------ | | enabled | boolean | true | Show or hide the sidebar | | component | (props: SidebarComponentProps) => ReactNode | — | Custom sidebar render function. Receives { tree, collapsible, flat }. Next.js only — other frameworks use slots. | | footer | ReactNode | — | Content rendered below nav items | | banner | ReactNode | — | Content rendered above nav items | | collapsible | boolean | true | Whether sidebar is collapsible on desktop | | flat | boolean | false | Render all items flat (Mintlify-style, no collapsible groups) | SidebarComponentProps Props passed to a custom sidebar component: | Property | Type | Description | | ------------- | ------------- | ------------------------------------------------ | | tree | SidebarTree | Full page tree with all parent-child relationships | | collapsible | boolean | Whether folders are collapsible | | flat | boolean | Whether folders are rendered flat | SidebarTree | Property | Type | Description | | ---------- | ---------------- | ------------------------ | | name | string | Root name (e.g. "Docs") | | children | SidebarNode[] | Top-level sidebar items | SidebarNode A union of SidebarPageNode | SidebarFolderNode. SidebarPageNode | Property | Type | Description | | -------- | --------- | ------------------- | | type | "page" | Node type | | name | string | Display name | | url | string | Page URL | | icon | unknown | Icon from registry | SidebarFolderNode | Property | Type | Description | | ------------- | ------------------ | ----------------------------- | | type | "folder" | Node type | | name | string | Display name | | icon | unknown | Icon from registry | | index | SidebarPageNode | Folder's landing page | | children | SidebarNode[] | Child pages and sub-folders | | collapsible | boolean | Whether this folder collapses | | defaultOpen | boolean | Whether it starts open | DocsTheme Theme configuration returned by theme factories. | Property | Type | Description | | -------- | ---------- | --------------------------------------------------- | | name | string | Theme identifier (e.g. "fumadocs", "darksharp") | | ui | UIConfig | Visual configuration — colors, typography, layout | Created via theme factories: UIConfig Fine-grained visual configuration passed to theme factories. | Property | Type | Description | | ------------ | -------------------- | ----------------------------------------------- | | colors | ColorsConfig | Theme color tokens | | typography | TypographyConfig | Font families, heading styles | | radius | string | Global border-radius (e.g. "0px", "0.5rem") | | layout | LayoutConfig | Content width, sidebar width, TOC settings | | codeBlock | CodeBlockConfig | Syntax highlighting and line numbers | | sidebar | SidebarStyleConfig | Sidebar visual style | | card | CardConfig | Card component styling | ColorsConfig All color tokens. Accepts any CSS color value (hex, rgb, oklch, hsl). | Token | Description | | --------------------- | ----------------------------------- | | primary | Primary brand color | | primaryForeground | Text color on primary backgrounds | | background | Page background | | foreground | Default text color | | muted | Muted background (e.g. code blocks) | | mutedForeground | Text on muted backgrounds | | border | Default border color | | card | Card background | | cardForeground | Card text color | | accent | Accent color | | accentForeground | Text on accent backgrounds | | secondary | Secondary color | | secondaryForeground | Text on secondary backgrounds | | popover | Popover/dropdown background | | popoverForeground | Popover text color | | ring | Focus ring color | LayoutConfig | Property | Type | Default | Description | | --------------- | --------- | ------- | ------------------------------- | | contentWidth | number | — | Max width of content area in px | | sidebarWidth | number | — | Sidebar width in px | | tocWidth | number | — | Table of contents width in px | | toc.enabled | boolean | true | Show table of contents | | toc.depth | number | 3 | Max heading depth for TOC | | header.height | number | — | Header height in px | | header.sticky | boolean | true | Sticky header | CodeBlockConfig | Property | Type | Default | Description | | ----------------- | --------- | ------- | -------------------------- | | showLineNumbers | boolean | false | Show line numbers | | showCopyButton | boolean | true | Show copy button | | theme | string | — | Shiki theme for light mode | | darkTheme | string | — | Shiki theme for dark mode | SidebarStyleConfig | Property | Type | Default | Description | | ------------- | --------------------------------------- | ----------- | ------------------------- | | style | "default" \| "bordered" \| "floating" | "default" | Sidebar visual style | | background | string | — | Background color override | | borderColor | string | — | Border color override | TypographyConfig FontStyle Used for each heading level and body text. | Property | Type | Description | | --------------- | ------------------ | ------------------------------------------------------------------ | | size | string | CSS font-size (e.g. "2.25rem", "clamp(1.8rem, 3vw, 2.5rem)") | | weight | string \| number | CSS font-weight (e.g. 700, "bold") | | lineHeight | string | CSS line-height (e.g. "1.2", "28px") | | letterSpacing | string | CSS letter-spacing (e.g. "-0.02em") | AIConfig RAG-powered AI chat. See Ask AI for usage guide. | Property | Type | Default | Description | | -------------------- | ---------------------------------------------------- | ----------------------------- | ------------------------------------------------------- | | enabled | boolean | false | Enable 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 | | triggerComponent | Component | — | Custom floating button component | | model | string | "gpt-4o-mini" | LLM model name (OpenAI-compatible) | | systemPrompt | string | auto-generated | Custom system prompt | | baseUrl | string | "https://api.openai.com/v1" | OpenAI-compatible API base URL | | apiKey | string | process.env.OPENAIAPIKEY | API key for the LLM provider | | maxResults | number | 5 | Number of doc pages to include as RAG context | | suggestedQuestions | string[] | — | Pre-filled questions shown when chat is empty | | aiLabel | string | "AI" | Display name for the AI assistant | | packageName | string | — | Package name the AI uses in import examples | | docsUrl | string | — | Base URL the AI uses for links | | loader | string | "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 }) => ReactNode | — | Custom loading component (overrides loader, Next.js only) | Floating styles | Style | Description | | -------------- | ----------------------------------------------------------------- | | "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. | Property | Type | Default | Description | | -------------- | -------------------------------- | --------------- | --------------------------- | | position | "above-title" \| "below-title" | "below-title" | Where to render the buttons | | copyMarkdown | boolean \| CopyMarkdownConfig | false | "Copy Markdown" button | | openDocs | boolean \| OpenDocsConfig | false | "Open in LLM" dropdown | CopyMarkdownConfig | Property | Type | Default | Description | | --------- | --------- | ------- | --------------- | | enabled | boolean | false | Show the button | OpenDocsConfig | Property | Type | Default | Description | | ----------- | -------------------- | ----------------- | ------------------ | | enabled | boolean | false | Show the dropdown | | providers | OpenDocsProvider[] | sensible defaults | LLM/tool providers | OpenDocsProvider | Property | Type | Description | | ------------- | ----------- | --------------------------------------------------------------------------------- | | name | string | Display name (e.g. "ChatGPT", "Claude") | | icon | ReactNode | Icon rendered next to the name | | urlTemplate | string | URL template. {url} is replaced with the page URL, {mdxUrl} with the MDX URL. | DocsMetadata SEO metadata configuration. | Property | Type | Default | Description | | --------------- | ------------------------------------ | ------- | ---------------------------------------------------------- | | titleTemplate | string | — | Page title template. %s is replaced with the page title. | | description | string | — | Default meta description | | twitterCard | "summary" \| "summarylargeimage" | — | Twitter card type | 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. | Property | Type | Default | Description | | -------------- | ----------------------- | ------- | ----------------------------------- | | enabled | boolean | false | Enable OG image generation | | type | "static" \| "dynamic" | — | Static images or dynamic generation | | endpoint | string | — | API endpoint for dynamic OG images | | defaultImage | string | — | Fallback OG image URL | Example (Next.js): In docs.config.tsx, 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). 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: | Property | Type | Description | | ------------- | ----------- | --------------------------------------------------------------------------------- | | title | string | Required. Page title, shown in sidebar and page heading | | description | string | Page description, used for meta tags and search | | icon | string | Icon key from the icons registry. Shows in sidebar. | | order | number | Sort order in the sidebar (only when ordering: "numeric"). Lower numbers first. | | tags | string[] | Tags for categorization | | ogImage | string | Shorthand for a single OG image path. Ignored if openGraph is set. | | openGraph | PageOpenGraph | Full Open Graph object (e.g. images: [{ url, width?, height? }]). When set, replaces generated OG from the config (e.g. dynamic endpoint). | | twitter | PageTwitter | Full Twitter card object (e.g. card, images). When set, replaces generated twitter metadata. | | hidden | boolean | If 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: Minimal example (shorthand ogImage or generated OG): Data types Frontmatter is YAML between the --- fences. Supported value types: | Type | Example in frontmatter | Use in framework fields | | --------- | ------------------------------ | -------------------------- | | string | title: "Hello" or title: Hello | title, description, icon, ogImage | | number | order: 1 | order | | boolean | hidden: true | Optional (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 - Next.js — The MDX pipeline uses remark-frontmatter and remark-mdx-frontmatter with name: "metadata". The parsed frontmatter is exposed as the metadata export from the page. The layout and generateMetadata receive it when resolving the page (e.g. via getPage(params)), and it is used for createPageMetadata, sidebar tree (title, icon, order), and description maps. - SvelteKit / Astro / Nuxt — The docs loader (e.g. import.meta.glob or content layer) reads each .md/.mdx file, parses frontmatter, and builds the nav tree and page data. Frontmatter is passed to the layout as page data (e.g. page.data or the props your content component receives). The same fields (title, description, icon, order, tags, ogImage) are used for sidebar, meta tags, and search. 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. extendTheme(base, overrides) Extend an existing theme with overrides. SvelteKit Server API createDocsServer(config) Creates all server-side functions for a SvelteKit docs site. Parameters: | Property | Type | Description | | ------------------- | ------------------------ | --------------------------------------------------------------------------- | | config | DocsConfig | The config object from defineDocs() | | _preloadedContent | Record | Pre-loaded markdown files from import.meta.glob. Required for serverless. | Returns: | Property | Type | Description | | -------- | ------------------------------ | ------------------------------------------------- | | load | (event) => Promise | Layout load function (use in +layout.server.js) | | GET | (event) => Response | Search endpoint handler | | POST | (event) => Promise | AI chat endpoint handler | SvelteKit Components Imported from @farming-labs/svelte-theme: | Component | Props | Description | | ------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------- | | DocsLayout | tree, config, title?, titleUrl? | Main layout with sidebar, nav, search, AI | | DocsContent | data, config | Page content with TOC, breadcrumb, footer nav | | DocsPage | entry, tocEnabled, breadcrumbEnabled, previousPage, nextPage, editOnGithub, lastModified | Low-level page wrapper (used by DocsContent) | Astro Server API createDocsServer(config) Same as SvelteKit — returns { load, GET, POST }. Parameters: | Property | Type | Description | | ------------------- | ------------------------ | --------------------------------------------------------------------------- | | config | DocsConfig | The config object from defineDocs() | | _preloadedContent | Record | Pre-loaded markdown files from import.meta.glob. Required for serverless. | Returns: | Property | Type | Description | | -------- | ----------------------------------------- | ----------------------------------------------------- | | load | (pathname: string) => Promise | Takes a URL pathname string, returns page data | | GET | ({ request }) => Response | Search endpoint handler for GET /api/docs?query=... | | POST | ({ request }) => Promise | AI chat endpoint handler with SSE streaming | Astro Components | Component | Import | Description | | -------------- | ------------------------------------------------------------- | -------------------------------------------------- | | DocsLayout | @farming-labs/astro-theme/src/components/DocsLayout.astro | Main layout with sidebar, search, and theme toggle | | DocsContent | @farming-labs/astro-theme/src/components/DocsContent.astro | Page content with metadata | | DocsPage | @farming-labs/astro-theme/src/components/DocsPage.astro | Page structure (TOC, breadcrumb, nav) | | ThemeToggle | @farming-labs/astro-theme/src/components/ThemeToggle.astro | Light/dark toggle | | SearchDialog | @farming-labs/astro-theme/src/components/SearchDialog.astro | Search + AI dialog | CSS Imports Same pattern as SvelteKit: | Import | Description | | -------------------------------------------- | ------------------------ | | @farming-labs/astro-theme/css | Default (fumadocs) theme | | @farming-labs/astro-theme/pixel-border/css | Pixel border theme | | @farming-labs/astro-theme/darksharp/css | Darksharp theme | Theme Factories | Factory | Import | | --------------- | ---------------------------------------- | | 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. Parameters: | Property | Type | Description | | ------------ | ------------ | -------------------------------------------------------- | | config | DocsConfig | The config object from defineDocs() | | useStorage | Function | Nitro's useStorage utility for accessing server assets | Returns: A Nitro event handler that responds to GET (page loading + search) and POST (AI chat) requests. 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: | Component | Props | Description | | ------------- | ------------------------------------- | --------------------------------------------- | | DocsLayout | tree, config, triggerComponent? | Main layout with sidebar, nav, search, AI | | DocsContent | data, config | Page content with TOC, breadcrumb, footer nav | CSS Imports | Import | Description | | --------------------------------------- | ------------------------ | | @farming-labs/nuxt-theme/fumadocs/css | Default (fumadocs) theme | Theme Factories | Factory | Import | | ------------ | ----------------------------------- | | 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. | Prop | Type | Default | Description | | ---------- | --------------------- | ----------------------------------- | --------------------------------------------------------------- | | search | SearchProviderProps | { options: { api: "/api/docs" } } | Search configuration. API defaults to the unified docs handler. | | theme | ThemeProviderProps | — | Theme provider options (passed to next-themes) | | children | ReactNode | required | Your app content | suppressHydrationWarning on ` 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. createDocsLayout(config) Creates the docs layout component from your config. Auto-generated by withDocs()` — you typically don't need to create this manually. --- ## Themes URL: https://farming-labs-docs.vercel.app/docs/themes Built-in themes and how to create your own Themes @farming-labs/docs ships with seven built-in themes. Each is a preset factory function that you pass to defineDocs(). Built-in Themes | Theme | Import | Description | | ----------------------------------------- | ---------------------------------- | --------------------------------------- | | Default | @farming-labs/theme | Neutral colors, standard radius | | Colorful | @farming-labs/theme/colorful | Warm amber accent, Inter typography | | Darksharp | @farming-labs/theme/darksharp | All-black, sharp corners | | Pixel Border | @farming-labs/theme/pixel-border | Inspired by better-auth.com | | Shiny | @farming-labs/theme/shiny | Clerk-inspired, purple accents | | DarkBold | @farming-labs/theme/darkbold | Pure monochrome, Geist typography | | GreenTree | @farming-labs/theme/greentree | Mintlify-inspired, emerald green accent | Using a Theme Don't forget the matching CSS import: Overriding Theme Defaults Every theme accepts an overrides object: Creating a Custom Theme For a comprehensive guide including publishing your theme as a package, see Creating Your Own Theme. Use createTheme() to build your own: Extending a Theme Use extendTheme() to modify an existing preset: --- ## Colorful URL: https://farming-labs-docs.vercel.app/docs/themes/colorful Warm amber accent with Inter typography and a clean layout Colorful Theme A warm, vibrant theme with an amber primary accent, Inter typography, and directional TOC styling. Usage Defaults | Property | Value | | ------------- | --------------------------- | | Primary | hsl(40, 96%, 40%) (Amber) | | Background | #ffffff | | Border | #e5e7eb | | Border radius | Standard | | Content width | 768px | | Sidebar width | 260px | | TOC style | Directional | Customizing --- ## Creating Your Own Theme URL: https://farming-labs-docs.vercel.app/docs/themes/creating-themes Step-by-step guide to building, publishing, and sharing custom themes Creating Your Own Theme Everything starts with createTheme(). No CSS required — just a config object. Quick Start That's it. Users can override any of your defaults: Config Options Reference Here's everything you can configure in createTheme(). name Unique identifier for your theme. Used for debugging and CSS scoping. ui.colors Color tokens mapped to --color-fd-* CSS variables at runtime. Any valid CSS color value works (hex, rgb, hsl, oklch). You only need to set the ones you want to change — the rest are inherited from the base preset. ui.typography Font families, heading sizes, weights, line heights, and letter spacing. Each heading/text style accepts these properties: | Property | Type | Example | | --------------- | ------------------ | --------------------- | | size | string | "2.25rem", "36px" | | weight | number \| string | 700, "bold" | | lineHeight | string | "1.2", "28px" | | letterSpacing | string | "-0.02em" | Tip: Use CSS variables for fonts so users can load them with next/font: ui.radius Global border radius. Maps to CSS --radius. ui.layout Content area dimensions and structural options. ui.codeBlock Code block rendering options. ui.sidebar Sidebar visual style. | Style | Description | | ------------ | ------------------------------------------------------- | | "default" | Standard fumadocs sidebar | | "bordered" | Visible bordered sections (inspired by better-auth.com) | | "floating" | Floating card sidebar with subtle shadow | ui.card Card styling. ui.components Default props for built-in MDX components. Full Example Here's a complete theme with every option: Extending an Existing Theme Don't want to start from scratch? Use extendTheme() to build on top of a built-in preset: Works with any built-in theme: extendTheme() returns a DocsTheme directly (not a factory). Use createTheme() when building a reusable preset. Cherry-Picking from Built-in Themes Each built-in theme exports its defaults object: Publishing as an npm Package Users install and use: Advanced: CSS Customization The config options above cover most use cases. But if you need pixel-level control over specific components — like how the sidebar active state looks, code block borders, table styling, or callout appearance — you can write a CSS file alongside your theme. How it Works Every theme can ship a CSS file that sits on top of the config. The CSS file: 1. Imports a color preset (which includes fumadocs-ui core styles) 2. Overrides CSS variables for light (:root) and dark (.dark) modes 3. Targets specific component selectors to customize their appearance Starting Point Two presets are available: | Preset | Import | Best for | | ------- | ------------------------------------- | ------------------ | | Neutral | @farming-labs/theme/presets/neutral | Light-first themes | | Black | @farming-labs/theme/presets/black | Dark-first themes | Component CSS Selectors Here are all the selectors you can target to style individual components: Sidebar Code Blocks Inline Code Tables Callouts Tabs Prev/Next Navigation Cards Search Dialog Breadcrumb Page Action Buttons Scrollbar Selection & Misc Tips - Inspect in DevTools — the fastest way to find the right selector is to right-click an element, inspect it, and check its classes/attributes. - Use !important sparingly — fumadocs uses Tailwind utilities, so some overrides need !important. Check the built-in theme CSS files for examples. - Scope with .dark — use .dark for dark mode styles. Fumadocs uses class-based dark mode. - Reference CSS variables — always use var(--color-fd-*) in your styles so they respond to user color overrides. - Look at built-in themes — the pixel-border and darksharp CSS files are excellent references showing every component selector in use. --- ## DarkBold URL: https://farming-labs-docs.vercel.app/docs/themes/darkbold Pure monochrome design with Geist typography and clean minimalism DarkBold Theme A pure monochrome design inspired by Vercel — featuring Geist typography, tight letter-spacing, and clean minimalism. Usage Defaults | Property | Value | | ------------- | ----------------- | | Primary | #000 (Black) | | Background | #fff | | Border | #eaeaea | | Border radius | Standard | | Content width | 768px | | Sidebar width | 260px | | Font | Geist, Geist Mono | Typography DarkBold uses the Geist font family with tighter letter-spacing for headings: - H1: 2.5rem, weight 600, letter-spacing -0.06em - H2: 2rem, weight 600, letter-spacing -0.04em - H3: 1.5rem, weight 600, letter-spacing -0.02em Customizing --- ## Darksharp URL: https://farming-labs-docs.vercel.app/docs/themes/darksharp All-black theme with sharp corners Darksharp Theme An all-black theme with rounded-none styling — clean, minimal, and sharp. Usage Defaults | Property | Value | | ------------- | ---------------------- | | Primary | Near-white | | Background | #000000 (pure black) | | Border radius | 0px (no rounding) | | Content width | 860px | | Sidebar width | 286px | Customizing --- ## Default URL: https://farming-labs-docs.vercel.app/docs/themes/default Clean, neutral palette with standard border radius Default Theme The default Fumadocs theme with a neutral color palette and standard border radii. Usage Defaults | Property | Value | | ------------- | ------------------ | | Primary | #6366f1 (Indigo) | | Background | #ffffff | | Border radius | Standard | | Content width | 768px | | Sidebar width | 280px | Customizing --- ## GreenTree URL: https://farming-labs-docs.vercel.app/docs/themes/greentree Mintlify-inspired theme with emerald green accent and Inter typography GreenTree Theme Inspired by Mintlify — a clean, modern design with an emerald green accent, Inter typography, and a compact sidebar. Usage Defaults | Property | Value | | ------------- | ------------------- | | Primary | #0D9373 (Emerald) | | Background | #fff | | Muted | #505351 | | Border | #DFE1E0 | | Border radius | Standard | | Content width | 768px | | Sidebar width | 240px | | Header height | 56px | Customizing --- ## Pixel Border URL: https://farming-labs-docs.vercel.app/docs/themes/pixel-border Inspired by better-auth.com — refined dark UI with visible borders Pixel Border Theme Inspired by better-auth.com — a clean dark UI with visible borders, pixel-perfect spacing, and a refined sidebar. The active sidebar indicator and text use your primary color. Usage Defaults | Property | Value | | ------------- | ----------------------------------------- | | Primary | Near-white (oklch(0.985 0.001 106.423)) | | Background | hsl(0 0% 2%) | | Border | hsl(0 0% 15%) | | Border radius | 0px | | Content width | 860px | | Sidebar width | 286px | Sidebar Features - Full-width border separators between top-level items - Collapsible folder groups with expand/collapse arrows - Active state: primary-colored text + left vertical indicator bar - Nested children are indented with smaller text - Folder parents use slightly muted text when collapsed Customizing The primary color flows to: - Active sidebar item text - Active sidebar indicator bar (::before) - Active TOC item - Links and other primary-colored elements --- ## Shiny URL: https://farming-labs-docs.vercel.app/docs/themes/shiny Clerk-inspired theme with purple accents and a polished light/dark design Shiny Theme Inspired by Clerk — a clean, polished UI with purple accents and a professional light/dark design. Usage Defaults | Property | Value | | ------------- | ------------------------------ | | Primary | hsl(256, 100%, 64%) (Purple) | | Background | #f7f7f8 | | Border | #e5e5ea | | Border radius | Standard | | Content width | 768px | | Sidebar width | 280px | | Header height | 64px | Customizing --- ## Token Efficiency URL: https://farming-labs-docs.vercel.app/docs/token-efficiency How @farming-labs/docs keeps your project lean for AI-assisted development — without sacrificing flexibility Token Efficiency AI tools like Cursor, Copilot, and Claude read your project files to help you write code. Every file they read costs tokens — the units that determine response speed, API cost, and how much of your project fits in a single conversation. @farming-labs/docs is built to keep the framework footprint small so more of your token budget goes to your actual documentation content — while still giving you the full flexibility of a modern docs framework. One Config, Full Control The core idea: everything about your docs site — theme, colors, typography, sidebar, AI chat, metadata — lives in a single docs.config.ts file. An AI agent reads this one file and immediately understands your entire docs setup — what theme you're using, where content lives, how AI chat is configured, how pages are titled. There's a provider wrapper (RootProvider) and a docs layout file, but they're minimal one-liners that the CLI generates for you. The real configuration surface is this single file. This matters because every additional config file, layout wrapper, or routing file is something an AI has to read, reason about, and avoid accidentally breaking. Fewer framework files means more room in the context window for what actually matters: your documentation content. The CLI Does the Heavy Lifting You don't have to set any of this up manually. The CLI scaffolds everything in seconds — for both new and existing projects. Starting from scratch Use --template to bootstrap a complete project with your framework and theme of choice: This creates a new my-docs/ folder with a fully working docs site — config, routes, CSS, sample pages, dependencies installed, dev server running. Pick from next, nuxt, sveltekit, or astro. Want a specific theme? Add --theme: That's it — a beautiful themed docs site in one command. Adding to an existing project Already have a Next.js, SvelteKit, Astro, or Nuxt project? Just run init inside it: The CLI auto-detects your framework from package.json, asks you to pick a theme, generates the config and minimal routing files, installs dependencies, and starts the dev server. Your existing code is untouched — it only adds what's needed for docs. See the CLI reference for all flags and options. Why This Matters for AI More context for your content AI models have limited context windows. Framework boilerplate eats into that budget. With @farming-labs/docs, the framework surface is roughly ~15 lines of config instead of hundreds of lines spread across many files. That leaves more room for your actual documentation pages when an AI is answering questions or making changes. Fewer files to reason about When an AI agent needs to modify your docs setup — change a theme, enable AI chat, adjust the sidebar — it reads your docs.config.ts and makes the change in one place. No hunting through layout files, provider trees, slug handlers, and CSS imports to figure out how everything connects. Less risk of breaking things A declarative config file is hard to break. An AI can add ai: { enabled: true } or change theme: darksharp() without worrying about import paths, component hierarchies, or routing logic. The framework handles all of that internally. Built-in AI Features Beyond being token-efficient to work with, @farming-labs/docs includes features designed for AI consumption: llms.txt Your docs are automatically served in LLM-optimized format — no extra routes needed: See the llms.txt docs for details. AI Chat with RAG Built-in AI chat with retrieval-augmented generation. A simple setup is just two lines: Need multiple models from different providers? Use the providers map and a model object with a selectable dropdown: Users get a model selector dropdown in the chat interface. The backend automatically routes each request to the correct provider with the right credentials. No separate API routes, no vector databases, no embedding pipelines — search indexing, context retrieval, and streaming responses are all handled internally. Works with any OpenAI-compatible provider: OpenAI, Groq, Together, Fireworks, OpenRouter, Ollama, or any vLLM deployment. See the AI Chat docs for the full configuration reference. Summary @farming-labs/docs keeps the framework lean — one config file, minimal routing, CLI-generated scaffolding — so you and your AI tools spend less time on plumbing and more time on content. And it does this without sacrificing flexibility: themes, multi-provider AI chat, search, custom components, and multi-framework support are all still there, just configured from one place. ---