---
title: AsciiBinder AsciiDoc to Markdown to Docusaurus
description: The same Markdown exported as a Docusaurus 3 project. MDX is stricter than Markdown, definition lists need a plugin, and the base URL has to be split in two. Measured on 1,800 pages and a real build.
created: "2026-09-05"
author: Gabriel McGoldrick
tags:
  - topic/asciidoc
  - topic/migration
---

# AsciiBinder AsciiDoc to Markdown to Docusaurus {#asciibinder-asciidoc-to-markdown-to-docusaurus}

The last part exported the OpenShift Markdown to MkDocs. This one takes the same pages to **Docusaurus 3**, which is a harder target. Docusaurus reads Markdown as MDX, and MDX is a programming language with Markdown syntax. A stray `{` or `<` that every other generator would print is a compile error here.

The site is at [dogsbay.github.io/openshift-docs-docusaurus](https://dogsbay.github.io/openshift-docs-docusaurus/docs/welcome/) and the workflow is [dogsbay/openshift-docs-docusaurus](https://github.com/dogsbay/openshift-docs-docusaurus).

:::note{title="AsciiDoc to Markdown — part 10 of 10"}
1. [Converting AsciiDoc to Markdown](/blog/converting-asciidoc-to-markdown/)
2. [Why existing AsciiDoc converters lose your structure](/blog/why-existing-converters-lose-structure/)
3. [Why Jinja is the right target](/blog/why-jinja-is-the-right-target/)
4. [Mapping AsciiDoc variables to Jinja](/blog/asciidoc-variables-in-jinja/)
5. [Mapping AsciiDoc conditionals to Jinja](/blog/asciidoc-conditionals-in-jinja/)
6. [Mapping AsciiDoc ifeval to Jinja](/blog/asciidoc-ifeval-in-jinja/)
7. [Mapping AsciiDoc includes and level offsets to Jinja](/blog/asciidoc-includes-in-jinja/)
8. [AsciiBinder AsciiDoc to Markdown to Astro](/blog/asciibinder-adoc-to-markdown-astro/)
9. [AsciiBinder AsciiDoc to Markdown to MkDocs](/blog/asciibinder-adoc-to-markdown-mkdocs/)
10. **AsciiBinder AsciiDoc to Markdown to Docusaurus** — you are here
:::

## The same flag, a different target {#the-same-flag-a-different-target}

```bash
npx dogsbay site build ./out --to docusaurus --out ./docusaurus \
  --site-url https://<you>.github.io/openshift-docs-docusaurus
```

The output is a complete Docusaurus project, not just content:

```
docusaurus/
  docusaurus.config.js   title, url + baseUrl, presets, remark plugins
  sidebars.js            the nav, as sidebar categories and doc ids
  package.json           Docusaurus 3 + the plugins the profile wired
  docs/                  1,799 pages, .md
  static/images/         675 files
  src/pages/index.js     the root redirect
```

`npm install && npx docusaurus build` produces the site. On GitHub's runners that is about nine minutes for 1,800 pages, most of it webpack.

Two things in that config are easy to get wrong by hand and the exporter does for you:

- **`url` and `baseUrl` are split.** Docusaurus rejects a path inside `url`, so `https://you.github.io/openshift-docs-docusaurus` becomes `url: "https://you.github.io"` and `baseUrl: "/openshift-docs-docusaurus/"`. Without the split, every link on a project Pages site 404s.
- **Number-prefixed filenames are not positions.** Docusaurus strips a leading `4-` from `4-years-of-k8s.md` and reads it as a sort key, so the doc id no longer matches the sidebar and the build fails on every such page. The config sets `numberPrefixParser: false` and orders from `sidebar_position` frontmatter instead.

## Markdown that compiles {#markdown-that-compiles}

Docusaurus is configured with `format: detect`. `.md` files are CommonMark, `.mdx` files are MDX. The exporter emits `.md`, which removes most of the danger, but not all of it, because the DogsBay directives become JSX components and the content inside them is MDX again. So the exporter carries an MDX repair pass with its own adversarial test suite: unclosed fences, closers with info strings, `\{` that must not double-escape, KaTeX, mis-nested tags, and prose that merely looks like a tag.

The OpenShift corpus contributed its own cases. Generated API reference pages contain `map<string, string>` in running text, and React rejects `string,` as a tag name. Those are escaped where the tag name is impossible and left alone where it is a real component. A `<pre>` from AsciiDoc's listing blocks is unwrapped by Docusaurus' MDXPre component unless it contains a `<code>`, so it gets one. And admonitions inside table cells, which Docusaurus' `:::` syntax cannot express, become Infima `alert alert--*` blocks.

| DogsBay MD | Docusaurus |
| --- | --- |
| `:::note`, `:::warning`, … | `:::note` admonitions, with the AsciiDoc kinds mapped to Docusaurus' five |
| `:::tabs` | `<Tabs>` / `<TabItem>`, values de-duplicated because Docusaurus requires them unique |
| `:::steps` | ordered lists, indented correctly at nesting depth |
| definition lists | `Term` / `: definition`, via `remark-definition-list` |
| related links | a list under the page, since a `related` fold has no native form |
| link buttons | a styled link, never dropped |

## Definition lists are a plugin, and that is the right call {#definition-lists-are-a-plugin-and-that-is-the-right-call}

OpenShift's API reference is thousands of definition lists. CommonMark has no syntax for them, and the obvious workaround, a bold term followed by a paragraph, loses the structure that makes a glossary a glossary.

The exporter wires `remark-definition-list` into the emitted config instead, so the Markdown keeps the `Term` / `: definition` form and the built HTML has real `<dl>`, `<dt>` and `<dd>` elements. This lives in an **export plugin profile**: the standard profile includes definition lists, math and Mermaid, and an `api` profile adds OpenAPI page generation.

One Docusaurus limitation is that the plugin renders definition lists at the top level and inside containers, but not nested inside list items. Those fall back to the bold-term form instead.

## Fidelity and links {#fidelity-and-links}

On the same bare-metal UPI page used to measure the MkDocs export: 166 of 166 code blocks, 117 of 117 admonitions, and the definition-list count within two of AsciiBinder's, for the same source-side reasons.

Links are where Docusaurus is strict in a useful way. `docusaurus build` checks every internal link and anchor and prints an exhaustive report.

Broken links are due to an issue in the AsciiDoc source itself. The workflow leaves them as warnings, and puts the report in the run summary.

## The home page issue {#the-home-page-issue}

The MkDocs blog post showed how the published site had no root page by default. Docusaurus had the same bug in a different shape. Docs live under `/docs/`, nothing is served at `/`, so the exporter emits a redirect page to the first page in the sidebar, `/docs/welcome/`.

## Try AsciiDoc to Docusaurus yourself {#try-asciidoc-to-docusaurus-yourself}

1. Fork [dogsbay/openshift-docs-docusaurus](https://github.com/dogsbay/openshift-docs-docusaurus).
2. In **Settings → Pages**, set the source to **GitHub Actions**.
3. Open the **Actions** tab, enable workflows, and run **Build Docusaurus site** against `enterprise-4.22`.

The workflow sparse-checks-out `markdown/` from the Markdown repo's content branch, exports, runs `npm install` and `docusaurus build`, commits the project to a same-named content branch, and deploys from the artefact. It also commits the resolved `package-lock.json` and reuses it on the next run, so when a dependency moves it shows up as a diff next to the build it broke.

Your copy appears at `https://<your-username>.github.io/openshift-docs-docusaurus/`.

## Pages to check {#pages-to-check}

| Page | Why |
| --- | --- |
| [/docs/welcome/glossary/](https://dogsbay.github.io/openshift-docs-docusaurus/docs/welcome/glossary/) | real `<dl>` from the plugin |
| [/docs/installing/installing_bare_metal/upi/installing-bare-metal-network-customizations/](https://dogsbay.github.io/openshift-docs-docusaurus/docs/installing/installing_bare_metal/upi/installing-bare-metal-network-customizations/) | the measured page |
| [/docs/rest_api/monitoring_apis/prometheus-monitoring-coreos-com-v1/](https://dogsbay.github.io/openshift-docs-docusaurus/docs/rest_api/monitoring_apis/prometheus-monitoring-coreos-com-v1/) | the largest page, generated API reference through MDX |
| [/docs/architecture/architecture/](https://dogsbay.github.io/openshift-docs-docusaurus/docs/architecture/architecture/) | images under `baseUrl` |
