---
description: Create, preview, and build a Doctrine site from scratch.
---

# Getting started

This guide starts with an empty project and ends with a deployable static site in `dist`.

## 1. Check the build environment

Doctrine requires Node.js 20.19 or newer and a
[native target supported by `@amamo/mdx`](https://jikkai.github.io/mdx/native-targets/). The native
compiler has no JavaScript fallback. MDX can execute JavaScript during bundling, prerendering, and
hydration, so use content and configuration from trusted authors only.

Install the package:

<InstallTabs packageName="@amamo/doctrine" />

Then create the content directory:

```sh
mkdir -p docs/guide
```

## 2. Add two pages

Create `docs/index.mdx`:

```mdx
# My project documentation

Choose a guide from the navigation.
```

Create `docs/guide/install.mdx`:

```mdx
# Install My project

<InstallTabs packageName="my-project" />
```

Neither page needs frontmatter. An optional string `description` becomes that page's meta
description.

## 3. Define the navigation

Each directory with MDX for a locale needs the matching navigation module. The root `docs/meta.ts`
orders the home page and child directory:

```ts
import { defineDirectory } from '@amamo/doctrine'

export default defineDirectory({
  items: [{ page: 'index', title: 'My project documentation' }, { directory: 'guide' }],
})
```

Create `docs/guide/meta.ts` beside the nested page:

```ts
import { defineDirectory } from '@amamo/doctrine'

export default defineDirectory({
  title: 'Guide',
  items: [{ page: 'install', title: 'Install My project' }],
})
```

The array controls exact sidebar order. `page` names a direct MDX basename; `directory` names a
direct child. The production build requires every page and child directory exactly once.

## 4. Start development

```sh
doctrine dev docs
```

Open `http://localhost:5173`. Vite server-renders each request and hydrates it in the browser. MDX
changes update through the content plugin; adding, removing, or editing navigation metadata refreshes
the route model without restarting the server.

Development tolerates a brief mismatch while a page and its `meta.ts` entry are saved separately.
The Pagefind development index is invalidated by content changes and rebuilt lazily on the next
search request.

Choose another interface or port when needed:

```sh
doctrine dev docs --host 0.0.0.0 --port 4173
```

## 5. Add optional site metadata

Create `doctrine.config.ts` in the directory where the CLI runs:

```ts
import { defineConfig } from '@amamo/doctrine'

export default defineConfig({
  title: 'My project documentation',
  description: 'Product guides and API notes for My project.',
  githubUrl: 'https://github.com/your-org/my-project',
})
```

Without a config file, the title is `Documentation`, the description is
`Documentation built from MDX.`, and `en` is the only locale.

## 6. Build the static site

Pass the real public URL, including any repository pathname:

```sh
doctrine build docs --site-url https://docs.example.com/
```

The default output is:

```text
dist/
├── 404.html
├── assets/
├── guide/install.md
├── guide/install/index.html
├── index.html
├── index.md
└── pagefind/
```

Doctrine builds client and SSR bundles, prerenders every navigation route, writes the authored MDX
at the matching `.md` paths, removes Vite's private manifest, and indexes the resulting HTML with
Pagefind. A repository URL such as
`https://user.github.io/my-project/` changes public URLs to `/my-project/...`; it does not create
`dist/my-project`.

## 7. Keep generated work out of Git

In addition to `dist`, Doctrine uses `.amamo-mdx/` for the generated content registry and cache
records, and `.doctrine/` for temporary build work. Add all three to the project's ignore file.

Continue with [Configuration](/configuration/) for every option, [Customization](/customization/)
for styling and overrides, [MDX components](/mdx-components/) for built-ins, or
[GitHub Pages](/deployment/) for a deployment workflow.
