---
description: Build and deploy a Doctrine site to GitHub Pages with the correct repository base path.
---

# Deploy to GitHub Pages

GitHub Pages project sites normally live at `https://owner.github.io/repository/`. Doctrine supports
that subpath when the build receives the final public URL.

## 1. Verify the production build locally

Use the same public shape before adding CI:

```sh
doctrine build docs --site-url https://owner.github.io/repository/
```

Open the generated `dist/index.html` through a static server if you want to exercise navigation and
search. Do not open it with a `file:` URL; module scripts and Pagefind expect HTTP serving.

## 2. Enable Actions deployment

In the repository, open **Settings → Pages** and set **Source** to **GitHub Actions**.

## 3. Add the workflow

Create `.github/workflows/deploy-docs.yml`:

```yaml
name: Deploy documentation

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  id-token: write
  pages: write

concurrency:
  group: pages
  cancel-in-progress: true

jobs:
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - id: pages
        uses: actions/configure-pages@v6
      - run: doctrine build docs --site-url "${{ steps.pages.outputs.base_url }}"
      - uses: actions/upload-pages-artifact@v5
        with:
          path: dist
      - id: deployment
        uses: actions/deploy-pages@v5
```

The versions match this repository's tested Pages toolchain. Change the branch, package manager,
content directory, or output directory to match the consuming project. Keep the upload `path` aligned
with `--out-dir` or `outDir`.

## Why `base_url` matters

`actions/configure-pages` returns the configured Pages URL, including `/repository/` for a project
site or the custom domain when present. Doctrine normalizes that URL and uses its pathname for:

- CSS and JavaScript assets
- default MDX links and navigation
- locale routes and language switching
- Pagefind requests and result links
- canonical and alternate metadata
- scripts and styles referenced by `404.html`

The artifact still contains `dist/index.html`, not `dist/repository/index.html`. GitHub Pages adds the
repository prefix while serving the artifact.

## Custom domains and other static hosts

The same workflow works after Pages is configured with a custom domain because `base_url` reflects
that setting. For another static host, run the same build with its final HTTP(S) URL and upload the
contents of the output directory. No production Node.js process is required.

## Troubleshooting

- **Workflow cannot deploy:** confirm Pages uses GitHub Actions and the job has `pages: write` plus
  `id-token: write`.
- **Assets, navigation, or search return 404:** ensure `--site-url` includes the complete repository
  pathname and ends at the public site root.
- **Artifact upload finds no files:** align `path` with `--out-dir` or configured `outDir`.
- **Build rejects `outDir`:** keep it inside the project root, outside the content directory, and do
  not use the root itself.
- **Native binding cannot load:** run on a platform supported by `@amamo/mdx` and install dependencies
  on that target instead of copying `node_modules` from another machine.
