Migrating

Migrating from MkDocs

Convert mkdocs.yml and its Markdown to a native Sourcey project, keeping every URL and anchor.

sourcey migrate mkdocs reads mkdocs.yml and docs_dir and writes a standalone Sourcey project next to them. Your Markdown stays where it is; only the syntax that needs a native form changes.

npx sourcey migrate mkdocs --dry-run

Configuration

MkDocsNative Sourcey
site_name, site_urlname, siteUrl and, for a site below a path, baseUrl
site_url: !ENV READTHEDOCS_CANONICAL_URL (any !ENV)the same variable, read when the native site builds
repo_url, edit_urirepo, editBranch, editBasePath, and the repository link in navbar.links
nav, or the default navigation without onenavigation groups, nested sections and external links
Material features: [navigation.tabs]a tab per top-level section
Material features: [navigation.path]navigation.breadcrumbs
Material's collapsed sidebar sections (navigation.sections, navigation.expand)collapsed groups, which open on the page they hold
Material frontmatter hide: [navigation], or a page's own templatelayout: page, the site's header and footer around the page; what has no native form (hide: toc alone, the template's HTML) is listed in the report
Material extra.analytics.feedback, frontmatter hide: [feedback]feedback with the same title, ratings, values and notes, and its emoticon or thumb icons as Heroicons; frontmatter feedback: false
use_directory_urlsprettyUrls
theme.logo, theme.favicon, Material palette.primary, fontlogo, favicon, theme.colors, theme.fonts
copyrightfooter.text
Material extra.socialfooter.links, where Material shows them; a link without a network's icon shows its name, or its host
site_author; Material extra.analytics with Google's property, or provider: custom and its partials/integrations/analytics/custom.html overridecomponents/Head.html, which every page's head ends with: the author's <meta>, Google's tag, or the partial as written
extra_javascriptcomponents/BodyEnd.html, where Material loads them, at the end of every page; a local script moves to public/ and keeps its address
mkdocs-redirects redirect_mapsredirects
git-revision-date, git-revision-date-localizedlastUpdated
strict: truebrokenLinks: "error"

Pages keep their URLs, including file names with capitals or underscores (markdown({ slugs: "file" })), and a README.md stays its directory's index. Where MkDocs built two files to one URL, the one it built last stays published and the report names the other. Pages that nav leaves out stay published, beside their nearest listed sibling and out of the menu. Heading anchors keep MkDocs's spelling. A page with no title or heading keeps the title MkDocs gave it from its nav label or file name. A CHANGELOG.md stays an ordinary page; remove changelog: false from the configuration to get native changelog pages and feeds.

With Material's navigation tabs, each top-level section becomes a native tab that publishes the folder its first page is in, so its pages keep their URLs; top-level pages are a tab at the docs root, which also keeps pages in no section's folder. A section that lists a page from another tab's folder links to it there, and the report names the page. When two sections start in the same folder, or no section starts at the root to keep the pages outside the others' folders, the sections stay top-level groups of one sidebar and the report says why.

MkDocs copies every other file in docs_dir to the site. Images and downloads a page uses are published with it. An HTML file is a page of its own, so it moves to public/, which native copies to the site root, and keeps its URL.

Markdown extensions

Each conversion applies only when the extension is enabled in mkdocs.yml.

ExtensionNative form
admonition:::note[Title] and the other callouts
pymdownx.details:::accordion[Title]
pymdownx.tabbed:::tabs with a :::tab[Label] per tab
GitHub alerts (gh-admonitions)unchanged; native Markdown reads > [!NOTE] as written, and an indented alert becomes a callout
pymdownx.snippets, markdown_include<Include src>; a fence holding only a snippet becomes a code include
attr_listheading IDs as {#id}; classes and other attributes are reported and removed
Material annotations ({ .annotate } with (1) markers and the list after them), footnotesfootnotes, numbered on through the page
md_in_htmlthe markdown attribute goes and the content is separated by blank lines
pymdownx.emoji icons, pymdownx.inlinehilite markersremoved and reported
pymdownx.highlight line optionsnative code fence metadata

MkDocs leaves raw HTML alone and copies docs_dir to the site, so <img src> paths in HTML are relative to the page URL and /images/... paths reach the copied files. The migration points each of those at its file, so native output publishes it.

Python-Markdown and CommonMark read a few things differently. A line opening with # is a heading to MkDocs even without a space after the hashes; the migration adds the space. A non-web address in angle brackets, such as hash<nlohmann::basic_json\>, is text to MkDocs; the migration escapes it so it stays text.

Custom extra_css is listed in the report rather than copied, since Material's stylesheet variables have no native meaning. So are the theme's other template overrides in custom_dir: a page part in components/, or pages/404.md for the not-found page, draws their place. A .readthedocs.yaml that builds with MkDocs is named too: switch its build to sourcey build.

What stops a migration

Plugins that generate content (macros, awesome-pages, mkdocstrings, i18n, blog and similar), a custom toc slugify, maths, and frontmatter that is not valid YAML stop the migration with the file and line. Fix or decide those once, then run it again.