Build a MkDocs Site from Word Documents (Walkthrough)
You have a folder of Word documents — internal handbook, API guide, runbook collection, training material — and you want them as a real documentation site with search, navigation, dark mode, and a public URL. MkDocs is the answer. Free, open source, ships beautiful templates out of the box, builds in seconds, deploys anywhere static. The path: convert each Word doc to Markdown, drop it in docs/, write a small mkdocs.yml, run mkdocs build. Here's the complete walkthrough.
What you'll end up with
A static site at https://yourname.github.io/yourdocs (or any host you want) with:
- Top-level tabs for sections
- Sidebar navigation with collapsible categories
- Full-text search with auto-suggest
- Dark/light theme toggle
- Code-copy buttons on all code blocks
- Permalinks on every heading
- Mobile-responsive layout
- Built-in admonitions (notes, warnings, tips)
All from the same Markdown that came out of your Word conversions. No CSS to write.
Step 1: Install MkDocs
pip install mkdocs mkdocs-materialThe Material theme is the de facto MkDocs theme — gorgeous out of the box, hugely configurable, used by FastAPI docs, Pydantic docs, and many others. Confirm install:
mkdocs --versionStep 2: Initialize the project
mkdir my-docs && cd my-docs
mkdocs new .This creates a starter structure:
my-docs/
├── docs/
│ └── index.md
└── mkdocs.ymlYou'll add converted Word docs into docs/ next.
Step 3: Convert each Word document
Take each .docx through the MDisBetter Word to Markdown converter one at a time:
- Drop .docx in the converter
- Click Convert
- Download the .md
- Save it in the appropriate
docs/subfolder with a kebab-case filename
For 30+ documents, install Pandoc and bulk-convert (see convert multiple Word documents):
cd /path/to/word-docs
for f in *.docx; do
base=$(echo "${f%.docx}" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
pandoc -f docx -t gfm \
--extract-media="$HOME/my-docs/docs/images" \
"$f" -o "$HOME/my-docs/docs/$base.md"
doneStep 4: Organise the docs folder
Group your converted .md files into logical sections:
docs/
├── index.md (landing page)
├── getting-started/
│ ├── installation.md
│ └── first-steps.md
├── guides/
│ ├── authentication.md
│ ├── data-import.md
│ └── deployment.md
├── reference/
│ ├── cli-commands.md
│ └── configuration.md
├── tutorials/
│ └── building-an-app.md
└── images/ (extracted from Word)Rename files to clear, lowercase, kebab-case slugs. Drop docs that are obsolete. Merge docs that overlap.
Step 5: Write mkdocs.yml
Replace the auto-generated mkdocs.yml with a configured version:
site_name: My Documentation
site_url: https://example.com
site_description: "Internal documentation, runbooks, and guides."
theme:
name: material
features:
- navigation.tabs
- navigation.sections
- navigation.expand
- navigation.top
- search.suggest
- search.highlight
- content.code.copy
- content.tabs.link
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: indigo
toggle:
icon: material/brightness-7
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: indigo
toggle:
icon: material/brightness-4
name: Switch to light mode
nav:
- Home: index.md
- Getting Started:
- Installation: getting-started/installation.md
- First Steps: getting-started/first-steps.md
- Guides:
- Authentication: guides/authentication.md
- Data Import: guides/data-import.md
- Deployment: guides/deployment.md
- Reference:
- CLI Commands: reference/cli-commands.md
- Configuration: reference/configuration.md
- Tutorials:
- Building an App: tutorials/building-an-app.md
markdown_extensions:
- admonition
- attr_list
- md_in_html
- tables
- toc:
permalink: true
- pymdownx.details
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
- pymdownx.inlinehilite
- pymdownx.snippets
plugins:
- searchStep 6: Preview locally
mkdocs serveOpen http://127.0.0.1:8000. The site auto-reloads as you edit. Verify:
- Navigation tabs across the top
- Sidebar with sections expanded
- Search bar in the header (try a query)
- Each page renders correctly with proper headings, lists, tables, code blocks
- Dark mode toggle works
- Images load (if you converted with --extract-media)
Step 7: Fix common conversion issues
Even with a clean conversion, you'll find a few things to polish:
Empty headings
Word styles sometimes generate empty heading paragraphs. Find them:
grep -rn '^#\+ \?$' docs/Delete them by hand.
Broken image references
If image paths in the .md don't match where you put the files:
grep -rn '!\[' docs/ | head -20Adjust the relative paths or rewrite them with sed.
Bad heading levels
Some Word docs start at H2 instead of H1, or skip levels (H1 → H3 → H2). MkDocs builds the table of contents from headings, so consistent levels matter. Open each top-level page and ensure the structure is sane.
Tables that didn't survive
Complex Word tables (merged cells, multi-row headers) often break in conversion. For those, consider replacing with a Markdown definition list, an admonition with bullet points, or a simpler flat table. See word tables to Markdown guide for tactics.
Step 8: Add admonitions and callouts
Word's "highlighted box" or "important note" styles don't survive conversion. Replace them with MkDocs admonitions:
!!! warning
Don't run this in production without testing.
!!! note
This applies only to v3.0 and later.
!!! tip
Use --dry-run to preview the changes.Worth doing for the most-read sections — instantly more scannable than the converted plain paragraphs.
Step 9: Build the site
mkdocs buildOutput goes to site/. Static HTML, CSS, and JS — no server needed. Upload to:
- GitHub Pages:
mkdocs gh-deploy - Netlify: drop the
site/folder, or connect to your Git repo - Cloudflare Pages: same
- Vercel: same
- S3 + CloudFront:
aws s3 sync site/ s3://mybucket --delete - Your own nginx/caddy server
Step 10: Continuous deployment
If your docs live in a Git repo, deploy on push. GitHub Actions:
name: Build & Deploy Docs
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.x' }
- run: pip install mkdocs-material
- run: mkdocs gh-deploy --forceNow every commit to main rebuilds and redeploys the site automatically. See migrate Word documentation to GitHub for the full docs-as-code workflow.
Bonus: instant search
The Material theme ships full-text search out of the box. For larger sites consider mkdocs-material-extensions or external search via Algolia DocSearch. Both index your Markdown and provide instant search-as-you-type.
Bonus: versioning
If you ship multiple versions of a product (v1, v2, v3 docs side by side), use the mike plugin:
pip install mike
mike deploy --push 3.0 latest
mike set-default --push 3.0Visitors get a version dropdown in the header.
What if some docs aren't Word?
If your knowledge base mixes Word with other source formats, convert each through the appropriate tool and drop into docs/:
- PDF to Markdown for vendor manuals and white papers
- URL to Markdown for web articles and external docs you want to mirror
- Audio to Markdown for recorded interviews and meetings worth indexing
All produce GFM-compatible .md that drops directly into the same MkDocs structure.
Why MkDocs over alternatives
| Tool | Best for | Tradeoff |
|---|---|---|
| MkDocs | Internal docs, project docs, runbooks | Limited customisation vs SPA generators |
| Docusaurus | Product docs with versioning + i18n | React-heavy, slower builds |
| Hugo | Marketing-style docs sites, blogs | Steeper learning curve, Go templating |
| Jekyll | GitHub-native, classic blog-style | Older, slower than alternatives |
| Sphinx | Python project docs, API references | RST-first, Markdown is bolted on |
For most teams converting from Word, MkDocs hits the sweet spot — beautiful output, minimal config, lives entirely in Markdown.
Plugins worth installing
The MkDocs ecosystem has a deep plugin catalogue. Worth knowing:
- mkdocs-material (theme) — covered above, the de facto modern theme
- mkdocs-redirects — set up redirects when you rename or move pages, so old URLs don't 404
- mkdocs-minify-plugin — minify HTML/CSS/JS in the built output for smaller bundle size
- mkdocs-git-revision-date-localized-plugin — auto-show "last updated" timestamps on each page from git history
- mkdocs-glightbox — click-to-enlarge for images (handy for screenshot-heavy docs from Word)
- mkdocs-print-site-plugin — generate a single printable page combining all docs (for PDF export)
- mkdocs-section-index — make section headings clickable (auto-link to a section's index page)
Add to mkdocs.yml under plugins: and pip install. Most are zero-config.
Common deployment patterns
Once your MkDocs site builds locally, you have several deployment options worth comparing:
- GitHub Pages: simplest if your repo is on GitHub. Free, custom domains supported, HTTPS by default. Run
mkdocs gh-deployor wire it into Actions. Perfect for OSS docs and small team docs. - Cloudflare Pages: connects to your Git repo, auto-builds on push, generous free tier, faster global edge than GitHub Pages. Ideal for production docs with global readership.
- Netlify: similar to Cloudflare Pages, slightly different feature set (form handling, edge functions). Same Git-connected auto-build flow.
- Vercel: also viable, particularly if you're already in the Vercel ecosystem for other projects.
- Self-hosted nginx: serve the
site/output as static files. Total control, more setup. Right for sensitive internal docs that can't go to a third-party host. - S3 + CloudFront: AWS-native, scales infinitely, costs pennies for small sites. Set up requires more work than the managed options.
For most teams, Cloudflare Pages or GitHub Pages is the right starting point. Switch to self-hosted only when you have a specific reason (compliance, internal-only, custom auth).
Performance optimisation
For sites over 500 pages, MkDocs build can become slow. Speed-ups:
- Use
mkdocs serve --dirtyreloadduring development (only rebuilds changed files) - Disable plugins you don't need on each build
- For very large sites (1,000+ pages), consider Hugo instead — it's faster but trades configurability for speed
Search at scale
The built-in lunr.js search is fine up to a few hundred pages. Beyond that, search becomes slow and the index becomes large. Alternatives:
- Algolia DocSearch — free for OSS docs, paid for commercial. Industry-standard for large doc sites.
- Meilisearch — self-hosted, fast, easy to set up
- Typesense — similar to Meilisearch, also self-hosted
All three integrate with MkDocs Material via official or community plugins.
Recommendation
Convert your Word docs progressively (web tool for one-offs, Pandoc for bulk), drop into docs/, configure mkdocs.yml, build, deploy. Total setup time for a 30-doc site: about 4 hours including reorg and polish. The result is a real documentation site you can hand a stranger and they can navigate. See migrate Word documentation to GitHub for the full docs-as-code workflow that pairs with this MkDocs setup. The combined approach — converted Markdown in docs/, version-controlled in Git, auto-deployed via CI on every push — turns a static Word library into a living documentation system.