Skip to content

how-to

Migrating a mkdocs.yml project in one upload

Zip the repository, upload it, and your mkdocs.yml is read for site name, description, language and navigation. What arrives intact, what a plugin was doing that no config can carry, and how to go back.

published · 6 min read

the short version

Zip the repository with mkdocs.yml at the root and upload it. Site name, description, language and the nav tree are read out, so your navigation survives without being rebuilt. What does not come across is anything a plugin or a theme override was doing.

Why this is the easy one

Of every migration on this site, a MkDocs project is the least work, and it is not close. Your content is already Markdown in a folder tree, your images already sit beside the pages that use them, and your navigation is already written down in a file we read.

There is a second reason, worth knowing if you run Material for MkDocs. Docszero builds with Zensical, which the Material for MkDocs team wrote as their own successor and released under MIT. This is not a migration out of the family — it is the same lineage, minus the pipeline.

Relevant background if you have not seen it: Material for MkDocs entered maintenance mode at version 9.7.0 in November 2025 — all Insiders features made free, sponsorware discontinued, bug and security fixes for at least twelve months and no new features, with the team’s attention moving to Zensical. The MkDocs comparison covers what that means for a self-hosted setup.

What is read out of mkdocs.yml

Four keys, and it is worth being exact, because "we read your config" is the kind of claim that means different things to different products.

KeyBecomes
site_nameThe site’s name
site_descriptionThe description, and the meta description
theme.language or site_languageThe site language
navThe navigation tree, with your titles and your order

That last one is the whole reason this is a one-upload migration. nav carries both the ordering and the human titles you chose, which are the two things a folder tree cannot express on its own:

the four keys that matter, and the tree that arrives intact
site_name: Acme Handbook
site_description: How to run and deploy Acme.

nav:
  - Home: index.md
  - Getting started:
      - Install: getting-started/install.md
      - First project: getting-started/first-project.md
  - Guides:
      - Deploying: guides/deploying.md
      - Troubleshooting: guides/troubleshooting.md
  - Reference: reference/cli.md

A zensical.toml works the same way, so a project already migrated to Zensical is read from that instead.

The steps

1. Zip the project

Include mkdocs.yml at the top level of the zip alongside your docs/ folder. If the config is buried a level down we will not find it, and you will get the folder tree without your nav — recoverable by dragging, but avoidable by zipping from the right place.

You do not need to strip anything. Extra files are ignored rather than rejected, so there is no need to prune requirements.txt, a CI workflow or an overrides/ folder before uploading.

2. Upload it

Up to 200 MB, which is a very large docs project. There is no build command to choose and no theme to install; the config is written for you from what we read.

3. Compare the tree against your nav

Open the page list next to your mkdocs.yml and check the order and the titles match. If nav was read, they will. If you had pages in docs/ that were not listed in nav — MkDocs simply appends those — they will be present here too, which is often the moment you discover a page nobody had linked for a year.

4. Deal with what the plugins were doing

The one real task, covered next. Everything else at this point is done.

5. Publish

Search is generated at publish time and served from the site, so whatever search plugin you were configuring is now not your problem. Navigation and a 404 page come with it.

What does not come across

Everything here has the same cause: it was produced by code running during your build, and the Markdown never contained it.

  • Plugin-generated pages. mkdocstrings reference built from docstrings, gen-files, literate-nav, an OpenAPI page. The generated output was never in your repository, so there is nothing to upload.
  • Theme overrides. An overrides/ folder with custom templates and partials. There are four themes, a brand colour and a logo instead.
  • Custom markdown_extensions. Standard Markdown, tables, code fences and mermaid all work. Exotic pymdownx extensions configured in your YAML do not carry their configuration.
  • Macros and variables. Anything substituted at build time by mkdocs-macros or similar arrives as the unsubstituted source.
  • Hooks. Python that ran during the build.
  • Versioned docs. If you run mike, each version is a separate build; there is one published site here, with rollback to earlier builds rather than parallel versions.

The honest read: if mkdocstrings is generating half your reference, this migration is not for you and self-hosting is the right answer. If your plugin list is a search plugin, a minifier and one or two conveniences, you are losing very little.

The five-minute check

Open mkdocs.yml and look at plugins: and markdown_extensions:. If both are short and mostly cosmetic, upload and you are done today. If either is doing content generation, stay where you are.

Going back, if you want to

Worth saying because the audience for this page owns their pipeline already and is being asked to give it up.

Export source hands back your Markdown with a generated config that builds with plain Zensical, nothing of ours involved, on every plan including Free. It is not a mkdocs.yml — it is the config for the generator we actually build with — but it is a working project, and your Markdown is unchanged from what you uploaded.

Which means the experiment is cheap. Copy your docs folder, import it on the free plan, look at the result, and either keep it or close the tab. You have not moved anything; the repository you have now is untouched throughout.

Questions

Does Docszero read my mkdocs.yml?

Yes, if it is at the top level of the uploaded zip. Site name, description, language and the nav tree are read out, so your navigation arrives with your titles and your ordering rather than needing to be rebuilt. A zensical.toml is read the same way.

What happens to my MkDocs plugins?

They do not come across, because plugins run during your build and their output was never in your repository. That matters most for content generation — mkdocstrings reference, gen-files, literate-nav, OpenAPI pages. If your plugin list is a search plugin and a couple of conveniences you are losing very little; if it is generating pages, self-hosting remains the right answer.

Do I need to remove anything from the repo before zipping?

No. Extra files are ignored rather than rejected, so requirements.txt, CI workflows and an overrides folder can stay. The only thing that matters is that mkdocs.yml sits at the top level of the zip beside your docs folder, so it is found.

Is Docszero the same as MkDocs?

No, but it is closely related. Docszero builds with Zensical, which the Material for MkDocs team wrote as their next-generation generator and released under MIT. Material for MkDocs itself entered maintenance mode at 9.7.0 in November 2025 with no new features planned, so Zensical is where that lineage continues either way.

Can I go back to self-hosting MkDocs afterwards?

Yes. Export source gives you your Markdown with a config that builds with plain Zensical, on every plan including Free. Your original repository is also untouched by the import, so trying this on a copy costs you nothing but the upload.

Try the free plan instead of reading about it

One site, your own docszero.com subdomain, full-text search and the export button, free forever and without a card. Pro is $19.99 a month when you want your own domain, your own look and the badge gone.

  • Drag in a folder of Markdown, a zip, a Word document or a PDF
  • Search, navigation and a 404 page are built for you
  • Export the built site or the source on every plan, free included