Skip to content
On This Page

Configuration

Doctrine works without a root config file. When present, it loads the first matching file in this order from the CLI working directory:

text
doctrine.config.ts
doctrine.config.mts
doctrine.config.js
doctrine.config.mjs

These are executable Vite config modules. defineConfig is a TypeScript identity helper; it does not sandbox or serialize the module.

TypeScript
import { defineConfig } from '@amamo/doctrine'

export default defineConfig({
  title: 'My project documentation',
  description: 'Product guides and API notes.',
  siteUrl: 'https://docs.example.com/',
  githubUrl: 'https://github.com/your-org/my-project',
  pageActions: true,
  copyright: 'Copyright © 2026 Your organization.',
  iconLibrary: 'lucide-react',
  outDir: 'dist',
  locales: {
    default: 'en',
    names: ['en', 'zh-CN'],
    labels: { en: 'English', 'zh-CN': '简体中文' },
  },
  components: './docs/components.tsx',
  styles: './docs/theme.css',
})

Site options

OptionTypeDefaultPurpose
titlestring"Documentation"Brand text and page-title suffix.
descriptionstring"Documentation built from MDX."Fallback meta description.
siteUrlstring"http://localhost/"Absolute public URL and Vite deployment base.
githubUrlstringnoneRepository link used by the header and MDX page actions.
githubSourceRootstringinferred inside the project rootContent path from the repository root for source links.
pageActionsbooleantrueEmit authored .md routes and show actions on MDX pages.
copyrightstringnoneFooter text.
iconLibrarystringnoneModule with named React icon exports used by navigation.
outDirstring"dist"Static output directory.
localesIDoctrineLocaleConfig{ default: "en", names: ["en"] }Locale routes, navigation sets, and switch labels.
componentsstringnoneCustom MDX component module.
stylesstringnoneCustom stylesheet loaded after Doctrine CSS.

title, description, and copyright are site-wide values. Put localized page descriptions in the corresponding MDX frontmatter or locale-specific navigation entry.

siteUrl must use HTTP or HTTPS and cannot contain a query or fragment. Doctrine normalizes its pathname with one leading and one trailing slash; that pathname becomes base. Set githubUrl to the HTTP or HTTPS URL of the GitHub repository. The header icon links to that URL. With page actions enabled, Open in GitHub appends blob/HEAD and the current locale's source path so GitHub opens the real MDX file on the repository's default branch. Doctrine normally derives that path from the content directory relative to the project root. In a monorepo where the project root is below the repository root, set githubSourceRoot to the content directory's repository-relative POSIX path, such as packages/docs/docs.

pageActions applies only to MDX document pages. Its default true value emits each page's authored MDX at the corresponding route-level .md URL and shows Copy Page, View as Markdown, and the conditional GitHub action. The source stays MDX and may contain frontmatter, imports, and JSX. Set the option to false to suppress both the .md output and page-action UI. Standalone TSX pages never receive either one, and the GitHub header link remains available independently.

Generated Markdown and HTML outputs must not claim the same file or a parent directory, and a generated .md path must not collide with a file under public/. Doctrine reports these conflicts before writing document pages instead of choosing one source silently.

Paths, precedence, and generated work

The CLI working directory is the project root. Relative paths are resolved from it; absolute paths are accepted where they still satisfy the build constraints.

  • The positional content directory defaults to docs, must exist, and is canonicalized.
  • components and styles must resolve to existing files and are canonicalized.
  • outDir is resolved from the root. It must be inside that root, cannot equal the root, and cannot be inside the content directory.
  • --site-url and --out-dir override the corresponding config values for a build.

The client build empties outDir before writing. Never point it at source or another valuable directory. Doctrine also creates .amamo-mdx/ for the generated content registry and cache records, plus .doctrine/ for temporary build work; keep both out of version control.

Directory navigation

Every directory containing MDX for a locale needs the corresponding TypeScript navigation module:

  • meta.ts for the default locale
  • meta.<locale>.ts for every translated locale present in that directory

defineDirectory is also an identity helper. The items array is the exact sidebar order:

TypeScript
// docs/meta.ts
import { defineDirectory } from '@amamo/doctrine'

export default defineDirectory({
  items: [
    {
      page: 'index',
      title: 'Overview',
      description: 'My project documentation overview.',
      icon: 'House',
    },
    { directory: 'guide' },
    { page: 'configuration', title: 'Configuration', icon: 'Settings' },
  ],
})

A child directory defines the group title and its direct contents:

TypeScript
// docs/guide/meta.ts
import { defineDirectory } from '@amamo/doctrine'

export default defineDirectory({
  title: 'Guide',
  icon: 'BookOpen',
  items: [{ page: 'install', title: 'Installation', icon: 'PackagePlus' }],
})

The root title is optional; nested navigation files require a non-empty title. Page entries may define a locale-specific description, which is used when the page has no frontmatter description. page must be a direct MDX basename without a slash, extension, or locale suffix. directory must be a direct child name and cannot be . or ...

Production requires every matching page and child directory exactly once. Duplicate entries, duplicate routes, invalid shapes, missing entries, and references that do not exist fail the build. Serve mode still validates shapes and duplicates but omits temporarily missing references and ignores unlisted new documents until navigation catches up.

Icons may appear on a page item or nested directory. Every icon name must use Doctrine's ASCII identifier form ($, _, or a letter first; digits allowed later) and be a named React component export from iconLibrary. Doctrine statically imports only the names present in navigation; a missing export fails bundling. iconLibrary is required when at least one icon is configured.

Routes and locales

locales.default must appear in locales.names; names must be unique and consist of alphanumeric segments separated by hyphens.

TypeScript
locales: {
  default: 'en',
  names: ['en', 'zh-CN', 'ja'],
  labels: {
    en: 'English',
    'zh-CN': '简体中文',
    ja: '日本語',
  },
}

Translated MDX uses filename suffixes:

text
docs/guide/install.mdx       -> /guide/install/
docs/guide/install.zh-CN.mdx -> /zh-CN/guide/install/
docs/guide/install.ja.mdx    -> /ja/guide/install/

The unsuffixed file belongs to the default locale. Navigation never falls back between locale files, and the language control appears only when another configured locale has the same slug. Missing locales.labels entries display the locale code.

Built-in interface labels are Chinese for locale names beginning with zh and English for every other locale. The exact configured locale still controls routes, navigation, metadata, and <html lang>.

Both index.mdx and page.mdx map to their containing directory. Do not create both for the same locale in one directory because they produce a duplicate route.

Frontmatter

Frontmatter is optional. Doctrine configures one public field:

MDX
---
description: A page-specific description used in HTML metadata.
---

When present, description must be a string. Page titles come from navigation, not frontmatter. MDX is executable content; schema validation does not make untrusted documents safe.

Custom components and styles

components points to a module whose default export is a React component map:

TSX
import type { IDoctrineComponents } from '@amamo/doctrine'
import type { ReactNode } from 'react'

interface INoticeProps {
  children: ReactNode
}

function Notice({ children }: INoticeProps) {
  return <aside className="project-notice">{children}</aside>
}

export default { Notice } satisfies IDoctrineComponents

The module is bundled into both SSR and the browser. It must render in Node.js; access browser-only globals from effects or event handlers, not during module initialization or rendering. Custom names override built-ins, including the default a link component.

Use styles for component CSS and theme variables. If the root package.json declares tailwindcss, Doctrine also enables the Tailwind Vite plugin. See Customization for styles and overrides, and MDX components for the built-in reference.

copyright © 2026 白熱。