Markdown-based static site publishing — no server, no database required. Write in markdown, build with Python, deploy anywhere.
Find a file
kbenestad d4f8a49f56
Merge pull request #9 from kbenestad/mdcms_cli
Opt into Node.js 24 for GitHub Actions
2026-05-09 12:55:27 +07:00
.github/workflows Opt into Node.js 24 for GitHub Actions 2026-05-08 17:10:02 +00:00
app Rebuild mdcms as proper CLI tool (v0.3) 2026-05-08 16:05:04 +00:00
docs Fix install.md: install from GitHub until mdcms is on PyPI 2026-05-09 01:19:53 +07:00
samplesite v0.2.2 migrated to GitHub 2026-04-20 00:02:43 +07:00
.gitignore v0.2.2 migrated to GitHub 2026-04-20 00:02:43 +07:00
CLAUDE.md Update CLAUDE.md: certifi dep, Node 24 workflow, branching convention 2026-05-09 00:11:00 +07:00
CONTRIBUTING.md Add LICENSE, CONTRIBUTING.md, and SECURITY.md 2026-05-09 02:55:19 +00:00
LICENSE Add LICENSE, CONTRIBUTING.md, and SECURITY.md 2026-05-09 02:55:19 +00:00
mdcms.py Fix SSL cert verification in PyInstaller binaries via certifi 2026-05-08 17:05:38 +00:00
pyproject.toml Fix build backend: use setuptools.build_meta instead of legacy 2026-05-09 01:26:10 +07:00
README.md Update README.md 2026-05-09 12:29:43 +07:00
SECURITY.md Add LICENSE, CONTRIBUTING.md, and SECURITY.md 2026-05-09 02:55:19 +00:00

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

  1. 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 mdcms code 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 dependenciesmdcms.py uses 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.

  1. Clone or download this repository.
  2. Run python3 mdcms.py and choose option 2 to build your config and folder structure from scratch.
  3. Write your pages in website/pages/ and posts in website/posts/.
  4. Run mdcms.py again and choose option 3 to generate nav.yml and search.json.
  5. Choose option 8 to start a local webserver and preview your site.
  6. When ready to publish, choose option 1 to validate, build, and export website.zip.
  7. Upload the contents of website.zip to your static host.

Local preview note: Open index.html via 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