---
title: Build a docs site
description: Pick the right leadtype integration shape for your docs app, and
  what each path gives you.
group: docs-site
order: 10
lastModified: "2026-05-13T22:39:22-07:00"
lastAuthor: Kaylee
---
# Build a docs site

Leadtype offers two integration shapes for a docs site. Pick the one that fits how your app is built — both produce the same content, just at different layers of your stack.

## Pick your path

```mermaid
flowchart LR
src["source MDX<br/>docs/*.mdx + meta.json"]
primitive["createDocsSource()<br/>(leadtype/mdx + leadtype/fumadocs)"]
cli["leadtype generate<br/>(CLI)"]
app["docs app<br/>(Next, Astro, Vite, Fumadocs)"]
artifacts["public/<br/>llms.txt · docs/*.md<br/>search-index · sitemap"]
src --> primitive --> app
src --> cli --> artifacts --> app
```

|Path|When to choose|What you wire|
|--|--|--|
|**Source primitive**|Most cases. You're building a Next, Vite, Astro, or Fumadocs app and compile MDX with your bundler.|`createDocsSource()` (or `leadtype/fumadocs`) + `createMdxSourcePlugins()`|
|**Static artifacts**|Your runtime needs flat files on disk (CDN-only deploy, static export, agent-only consumption, multi-app sharing).|`leadtype generate` CLI in your build script|

The two paths are not mutually exclusive — you can use the source primitive for your UI and still run `leadtype generate` for the `llms.txt` and agent-readability artifacts.

## Source primitive: the common path

If your docs app compiles MDX through a bundler, use the source primitive. It gives your runtime:

* `loadPage(slug)` returning frontmatter + AST + serialized markdown + TOC
* `getNavigation()` returning the resolved group tree
* `buildSearchIndex()` returning a static search index
* `resolveInclude()` for programmatic partial loading

→ [Use the source primitive](/docs/build/use-the-source-primitive) — generic recipe
→ [Integrate with Fumadocs](/docs/build/integrate-with-fumadocs) — first-party adapter

## Static artifacts: the CLI path

If your runtime needs files on disk — for a CDN-only deploy, a static export, a separate agent-only service, or to share artifacts across multiple sibling apps — run the CLI. It writes:

* `public/llms.txt` and `public/llms-full.txt`
* `public/docs/*.md` (markdown mirrors)
* `public/docs/search-index.json` + `search-content.json`
* `public/docs/sitemap.xml`, `sitemap.md`, `robots.txt`, `agent-readability.json`

→ [Generate static artifacts](/docs/build/generate-static-artifacts) — CLI workflow

## Add the cross-cutting features

Whichever path you pick, the same follow-on guides apply:

* [Add search](/docs/build/add-search) — local search index + optional source-grounded answers
* [Optimize docs for agents](/docs/build/optimize-docs-for-agents) — markdown responses, llms.txt, discovery files
* [Validate in CI](/docs/build/validate-in-ci) — lint frontmatter, meta.json, internal links

## Configure product and groups

Both paths read the same `docs/docs.config.ts`. Source repos own this file so groups and product metadata version with the docs:

```ts
import { defineDocsConfig } from "leadtype";

export default defineDocsConfig({
  product: {
    name: "c15t",
    summary: "Consent infrastructure for modern web apps.",
    bullets: ["Framework integrations.", "Consent primitives.", "Audit-friendly docs."],
    bestStartingPoints: [{ urlPath: "/docs" }, { urlPath: "/docs/quickstart" }],
  },
  groups: [
    { slug: "get-started", title: "Get Started" },
    { slug: "guides", title: "Guides" },
    { slug: "reference", title: "Reference" },
  ],
});
```

Pages declare `group:` in frontmatter; the config declares titles, order, and descriptions. See [Frontmatter](/docs/authoring/frontmatter) for the page-level schema.
