Configuration
Doctrine works without a root config file. When present, it loads the first matching file in this order from the CLI working directory:
doctrine.config.ts
doctrine.config.mts
doctrine.config.js
doctrine.config.mjsThese are executable Vite config modules. defineConfig is a TypeScript identity helper; it does not
sandbox or serialize the module.
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
| Option | Type | Default | Purpose |
|---|---|---|---|
title | string | "Documentation" | Brand text and page-title suffix. |
description | string | "Documentation built from MDX." | Fallback meta description. |
siteUrl | string | "http://localhost/" | Absolute public URL and Vite deployment base. |
githubUrl | string | none | Repository link used by the header and MDX page actions. |
githubSourceRoot | string | inferred inside the project root | Content path from the repository root for source links. |
pageActions | boolean | true | Emit authored .md routes and show actions on MDX pages. |
copyright | string | none | Footer text. |
iconLibrary | string | none | Module with named React icon exports used by navigation. |
outDir | string | "dist" | Static output directory. |
locales | IDoctrineLocaleConfig | { default: "en", names: ["en"] } | Locale routes, navigation sets, and switch labels. |
components | string | none | Custom MDX component module. |
styles | string | none | Custom 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. componentsandstylesmust resolve to existing files and are canonicalized.outDiris resolved from the root. It must be inside that root, cannot equal the root, and cannot be inside the content directory.--site-urland--out-diroverride 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.tsfor the default localemeta.<locale>.tsfor every translated locale present in that directory
defineDirectory is also an identity helper. The items array is the exact sidebar order:
// 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:
// 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.
locales: {
default: 'en',
names: ['en', 'zh-CN', 'ja'],
labels: {
en: 'English',
'zh-CN': '简体中文',
ja: '日本語',
},
}Translated MDX uses filename suffixes:
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:
---
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:
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 IDoctrineComponentsThe 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.