| .github/workflows | ||
| app | ||
| docs | ||
| samplesite | ||
| .gitignore | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| mdcms.py | ||
| pyproject.toml | ||
| README.md | ||
| SECURITY.md | ||
MD-CMS
Markdown-based static site publishing
MD-CMS lets you write and publish a website entirely in markdown. Drop your .md files in a folder, run the build tool, upload the output to any static host, and you're done. All rendering happens in the browser.
Installation
- Download the latest release for your
How it works
MD-CMS has two parts:
index.html — a single-file browser renderer. It reads your markdown files, config, and navigation at runtime and renders everything client-side. No build pipeline, no framework, no compilation step.
mdcms.py — a zero-dependency Python CLI tool. It scans your content, generates nav.yml and search.json, validates your config, and packages everything into a zip file ready for upload.
Features
- Write in markdown — pages and posts with YAML frontmatter
- Categories — serve multiple versions of the same page (e.g. languages, destinations, variants) via
?cat=URL parameter and a dropdown UI - Sections — nested navigation defined in
nav.yml; pages declare their section via frontmatter - Full-text search — category-aware, generated at build time
- Dynamic content tags — embed post lists with date sorting, pagination, and year grouping using fenced
mdcmscode blocks - RTL support — per-category text direction
- Custom fonts per category — load a font file from
assets/fonts/when a category is selected - Light and dark mode — fully themeable via
config.yml - No server required — everything is static; deploy to GitHub Pages, Codeberg Pages, Cloudflare Pages, Netlify, or any file host
- Zero dependencies —
mdcms.pyuses only the Python standard library
File structure
mdcms.py ← build tool, run this
quickstart.md ← getting started guide
website/ ← everything in here gets deployed
index.html
config.yml
nav.yml
search.json
pages/
home.md
about.md
about.nb.md ← Norwegian variant of about.md
posts/
2025-01-01-my-first-post.md
assets/
images/
fonts/
The website/ folder is your deployable site. mdcms.py lives outside it.
Getting started
Requirements: Python 3 (standard library only). A modern browser.
- Clone or download this repository.
- Run
python3 mdcms.pyand choose option 2 to build your config and folder structure from scratch. - Write your pages in
website/pages/and posts inwebsite/posts/. - Run
mdcms.pyagain and choose option 3 to generatenav.ymlandsearch.json. - Choose option 8 to start a local webserver and preview your site.
- When ready to publish, choose option 1 to validate, build, and export
website.zip. - Upload the contents of
website.zipto your static host.
Local preview note: Open
index.htmlvia the built-in webserver (option 8), not by double-clicking the file. Browsers block local file access due to CORS restrictions.
Configuration
Site behaviour is controlled by two YAML files in website/:
config.yml — site title, logo, default page, search settings, typography, layout dimensions, light/dark theme colours, and category definitions.
nav.yml — navigation structure. Sections are defined here; pages declare their section via section-id in frontmatter. Sections can be nested.
Both files are human-readable and comment-supported. The mdcms.py wizard generates them for you and can fill in missing values interactively.
Categories
Categories let you publish multiple versions of the same page — different languages, regions, or product variants — under a single URL with a ?cat= parameter.
Each variant is a separate file:
about.md ← default
about.en-gb.md ← British English variant
about.nb.md ← Norwegian variant
The category dropdown shows only categories for which a variant exists (or where a "not available" message is configured). All internal links preserve the active category.
Tag system
Embed dynamic post lists in any page using fenced mdcms code blocks:
```mdcms
posts-date-reversechronological
limit: 10
paginate: yes
```
Available tags cover chronological and reverse-chronological post lists, grouped by year, with date or datetime display, and configurable pagination.
Licence
Apache 2.0 — see LICENCE.
© Kristian Benestad