mkdocs-material-to-starlight
v0.5.4
Published
Migrate MkDocs Material sites to Astro Starlight in one command. Maps pages, plugins, sidebar, redirects, and i18n; reports anything left over with file:line diagnostics.
Downloads
839
Maintainers
Readme
mkdocs-material-to-starlight
Convert an MkDocs Material site to Astro Starlight.
The converter reads mkdocs.yml and writes a buildable Starlight project with converted pages, navigation, redirects, and locales. It records unsupported syntax and plugins in MIGRATION_NOTES.md with file and line numbers.
Quick start
npx mkdocs-material-to-starlightThe wizard reads mkdocs.yml, asks about site-specific choices, and writes to ./starlight-out. Requires Node 22.12+.
cd ./starlight-out
npm install
npm run devPreview the plan without writing files:
npx mkdocs-material-to-starlight ./my-mkdocs --explain
Generated projects use Astro and Starlight without silently installing community plugins. The TUI offers starlight-sidebar-topics when it detects navigation tabs and starlight-links-validator under advanced options; both default to No. Other integrations, including whole-page Copy Markdown, are recommendation-only in MIGRATION_NOTES.md. CLI users can opt in with --sidebar-topics or --links-validator.
What it converts
| MkDocs Material | Starlight output |
|---|---|
| !!! note "Title" admonitions (12 types) | :::note[Title] aside directives; a generated Astro 7-native remark plugin preserves abstract, info, question, success, failure, bug, and example |
| ??? note / ???+ note collapsible | <details><summary>Title</summary>...</details> |
| === "Tab" content tabs | Starlight <Tabs>/<TabItem> MDX components (default; --tabs html keeps .md with a shim) |
| <div class="grid cards" markdown> | <div class="sl-card-grid">…</div> |
| <div class="grid" markdown> | <div class="sl-grid">…</div> |
| :material-rocket: / :fontawesome-brands-github: | :icon[rocket] / :icon[github], with curated name mapping plus SVG fallback |
| --8<-- "snippet.md" | Inlines snippet content (with cycle detection and depth limit) |
| ==text== highlights | <mark>text</mark> |
| H~2~O subscripts and 2^10^ superscripts | <sub> and <sup> |
| ++ctrl+alt+del++ keyboard keys | <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Del</kbd> |
| [link](api/auth.md) internal refs | Rewritten to Starlight slugs ([link](/api/auth)) |
| Footnotes ([^1]) | GFM footnotes via remark-gfm |
| Math ($inline$, $$block$$) | Preserved; migration notes recommend an optional math pipeline |
| ```mermaid blocks | Preserved; migration notes recommend an optional Mermaid integration |
| MagicLink autolinks (@user, #123) | Markdown links pointing at GitHub from repo_url |
| Definition lists, abbreviations, buttons, CriticMarkup, code annotations | Normalized to standard Markdown or styled HTML |
| MkDocs | Starlight output |
|---|---|
| nav: tree | sidebar config in astro.config.mjs |
| No nav: tree | Complete sidebar synthesized from the docs directory tree, with software-aware group casing |
| site_name, site_description, site_url | title, description on the integration; site on Astro config |
| site_url with a subpath (GitHub Pages project sites) | Astro base:; migration notes flag content links needing review |
| theme.features: navigation.tabs | Standard grouped sidebar; --sidebar-topics explicitly opts into the community plugin |
| theme.features: navigation.top | Migration note recommending the optional scroll-to-top plugin |
| theme.features: announce.dismiss / content.action.view | Migration notes recommending optional plugins |
| draft_docs | Matching files receive draft: true; production filtering remains an explicit plugin choice |
| Missing frontmatter title | Synthesized from first H1 or a software-aware humanized filename (Starlight requires it) |
| Missing 404 page | Minimal styled 404.md scaffolded (skipped when the source converts its own) |
| MkDocs plugin | Starlight output |
|---|---|
| mkdocs-redirects | redirects: { … } in astro.config.mjs |
| mkdocs-static-i18n | Directory-prefix layout (fr/page.md) plus locales: { … }; recommends the optional starlight-i18n editor extension |
| mkdocs-section-index | Section index.md hoisted to first child of its sidebar group |
| mkdocs-literate-nav | SUMMARY.md parsed and used as the nav source |
| mkdocs-include-markdown-plugin | {% include %} resolved inline before conversion |
| mkdocs-rss-plugin | @astrojs/rss dep plus src/pages/rss.xml.ts scaffold |
| mkdocs-glightbox | Recommends optional starlight-image-zoom |
| mike (versioned docs) | Recommends optional starlight-versions |
| mkdocs-git-revision-date-localized | Built-in lastUpdated: true |
| blog, tags (Material) | Recommends optional starlight-blog and starlight-tags |
| social (Material, per-page OG cards) | Recommends an explicitly selected OG-image integration |
| mkdocs-d2-plugin | Recommends an optional D2 integration |
| Giscus comments (overrides/partials/comments.html) | Records parsed repo/category IDs and recommends explicit integration |
| mkdocs-swagger-ui-tag | Recommends optional starlight-openapi |
| mkdocs-macros-plugin (Jinja2) | Diagnostic at each occurrence with a file and line locator |
| mkdocs-puml / plantuml-markdown | Diagnostic: astro-plantuml still peers astro@^5 and won't resolve against the Astro 7 stack |
| Interactive pymdownx.superfences.custom_fences | Diagnostic recommending astro-live-code and a renderable language fence with the live metadata flag |
| mkdocs-print-site-plugin | Recommends starlight-to-pdf for PDF artifacts; documents the custom print.astro path for combined HTML |
| gen-files, monorepo, multirepo, meta, privacy, mkdocstrings, mkdocs-jupyter | Diagnostic in MIGRATION_NOTES.md with documented workaround |
Output
output/
├── astro.config.mjs ← migrated config: sidebar, redirects, locales, plugins
├── package.json ← scripts and pinned dependencies
├── biome.json ← formatter and linter config
├── MIGRATION_NOTES.md ← human-readable diagnostics, grouped by rule
├── public/ ← non-Markdown assets (images, PDFs) copied through
└── src/
├── content.config.ts ← docs collection wired to Starlight's loader/schema
├── content/docs/ ← converted Markdown pages and a 404 page
└── styles/mkdocs-migration.css ← styles for grids, cards, and tabsRun cd output && npm install && npm run dev to start the converted site.
Common workflows
# Interactive conversion
npx mkdocs-material-to-starlight
# Unattended conversion with wizard defaults
npx mkdocs-material-to-starlight ./mkdocs-project ./starlight-out --yes
# Print the migration plan without writing files
npx mkdocs-material-to-starlight ./mkdocs-project --explain
# Run astro check on the output
npx mkdocs-material-to-starlight ./mkdocs-project ./starlight-out --yes --check
# Resolve PyMdown snippets from a custom directory
npx mkdocs-material-to-starlight ./mkdocs-project ./starlight-out \
--yes --snippet-base-path docs --snippet-base-path includesDiagnostics
The converter reports bad input as typed diagnostics and continues with the remaining files.
In your terminal:
api/auth.md:12:4 warning broken-link link target "missing.md" was not found in the slug mapoutputDir/MIGRATION_NOTES.md groups diagnostics by rule and file. It also lists unmapped mkdocs.yml fields and workarounds for unsupported plugins. Run --explain to print each rule's description and fix before conversion.
CLI reference
mkdocs-material-to-starlight <project-dir> <output-dir> [options]
mkdocs-material-to-starlight <project-dir> --explain
mkdocs-material-to-starlight compare <baseline-url> <converted-url> [options]
Convert options (run `--help` for the full list):
--snippet-base-path <path> Resolve PyMdown snippets against this directory.
Repeatable; first match wins.
--check / --no-check Run `astro check` against the output and surface
its diagnostics. Needs `npm install` in the output
directory first; reports the missing install otherwise.
--check-timeout <ms> Override the astro-check timeout (default: 10min).
--sidebar-topics Install starlight-sidebar-topics for nav.tabs
--no-sidebar-topics Keep the flat sidebar instead.
--tabs <mdx|html> Tabs output strategy (default: mdx).
--palette <translate|skip|custom> Palette handling (default: translate).
--dry-run Plan only, do not write files. (Not yet wired through.)
--yes Accept wizard defaults; skip interactive prompts.
Compare options (visual diff between rendered MkDocs and Starlight pages):
--pages a,b,c Comma-separated paths to diff (default: /).
--threshold 0.01 Mismatch ratio that still counts as a match.
--report file.md Write the Markdown report to a file instead of stdout.
Common:
-h, --help Show help.
--version Print the version.Exit codes: 0 success, 1 runtime or check failure, 2 usage error.
Install the compare peer dependencies before using that subcommand:
npm install playwright pixelmatch pngjs
npx playwright install chromiumProgrammatic API
import { convertSiteFromDisk } from 'mkdocs-material-to-starlight';
const result = await convertSiteFromDisk({
projectDir: '/path/to/mkdocs-project',
outputDir: '/path/to/output',
snippetBasePaths: ['docs'], // optional; enables snippet expansion
});
if (!result.ok) {
console.error(`${result.error.code}: ${result.error.message}`);
process.exit(1);
}
for (const tagged of result.value.diagnostics) {
console.log(`${tagged.sourcePath}: ${tagged.diagnostic.ruleId}: ${tagged.diagnostic.message}`);
}The success result exposes astroConfigSource, packageJsonSource, migrationNotesSource, and sidebarSource for custom write strategies.
Limitations
- The converter maps theme palettes to Starlight custom properties, fonts to Fontsource packages, and extra assets to
customCssorheadentries. It records customoverrides/templates inMIGRATION_NOTES.md. Review translated colors against the Starlight theme. - The converter cannot evaluate
mkdocs-macros-pluginJinja2 expressions. It reports each{{ … }}and{% … %}occurrence with its file and line. mkdocs-section-indexandmkdocs-literate-navsupport standard layouts. They do not support recursive per-directorySUMMARY.mdfiles or implicit indexes for entries outsidenav:.--dry-runhas no effect. Use--explain.
Architecture
The converter uses unified and remark.
- Each transform owns a disjoint MDAST
(node-type, name)namespace, so plugin order does not change output. - A second conversion produces byte-identical output:
convert(convert(x)) === convert(x). - Input failures produce typed diagnostics instead of exceptions.
- Pure logic lives in
domain/anduse-cases/;infrastructure/handles I/O through ports.
src/
├── domain/ Pure types, value objects, ports (no I/O, no framework deps)
├── use-cases/ Application orchestration; functional core
├── infrastructure/ Adapters for file system, YAML, unified; the imperative shell
└── interface/ CLI and programmatic API; the only place that wires concrete adaptersSee each layer's README for import rules: src/domain/, src/use-cases/, src/infrastructure/, and src/interface/.
Development
Requires Node 20.19+.
npm install
npm test # full suite, runs in ~10s
npm run typecheck # tsc --noEmit
npm run build # emit dist/
npx vitest run path/to/file.test.ts # single test file
npx vitest run -t 'pattern matches subject' # single test by titleReport bugs and submit fixtures at github.com/sitapix/mkdocs-material-to-starlight/issues.
License
MIT © sitapix
