Skip to content

All.publish mkdocs.how to guide

How to Publish Mkdocs Documentation#

Overview#

At Causify, we use MkDocs with the Material theme to publish documentation for multiple projects. We have two main publishing methods:

  1. Custom domain with S3 (e.g., https://docs.causify.ai) - VPN-protected internal documentation
  2. GitHub Pages (e.g., https://causify-ai.github.io/helpers) - Public documentation

Both methods follow the same structure and workflow, with only minor variations in the deployment step.

Publishing Options#

Option 1: Custom Domain (S3 + VPN)#

Use case: Internal documentation that should be VPN-protected

Infrastructure:

  • S3 bucket for static hosting
  • CloudFront distribution (optional, for caching)
  • VPN → VPC → Load Balancer → S3 VPC Endpoint → S3 bucket
  • Custom subdomain (e.g., docs.causify.ai)

Examples:

Workflow: GitHub Action builds MkDocs → syncs to S3 → invalidates CloudFront cache Example:-Causify doc Git Action

Option 2: Github Pages#

Use case: Public documentation that should be accessible without VPN

Infrastructure:

  • GitHub Pages hosting (free)
  • Automatic HTTPS via GitHub
  • URL format: https://<org>.github.io/<repo>/

Examples:

Workflow: GitHub Action builds MkDocs → pushes to gh-pages branch → GitHub Pages serves it

Directory Structure#

Required Layout#

Every MkDocs site we publish must follow this exact directory and file layout:

<site-root>/
    mkdocs.yml                # Site configuration (docs_dir points to tmp.mkdocs)
    docs/                     # Raw source content (committed to git)
        index.md                # Homepage
        <other .md files>       # Documentation pages
        <folders>/              # Organized documentation sections
        assets/                 # Images and icons
            logo.png              # Site logo (symlink or real file)
            favicon.ico           # Site favicon (symlink or real file)
        styles/                 # Custom CSS
            styles.css            # Main stylesheet (symlink or real file)
    tmp.mkdocs/               # Preprocessed content (DO NOT COMMIT)
        index.md                # Processed files
        <other processed files>
        assets/                 # Copied assets
        styles/                 # Copied styles

File Descriptions#

mkdocs.yml

  • Main configuration file for the site
  • Defines site name, theme, plugins, and markdown extensions
  • Critical: docs_dir: tmp.mkdocs points to preprocessed content

docs/

  • Contains raw markdown files that you write and edit
  • This is what gets committed to git
  • Organized with folders for different documentation sections

docs/assets/

  • Logo, favicon, images, diagrams
  • Should be symlinked to canonical versions (see below)

docs/styles/

  • Custom CSS for site styling
  • Should be symlinked to canonical stylesheet

tmp.mkdocs/

  • Generated by the preprocessing script
  • Never commit this directory to git (add to .gitignore)
  • This is what MkDocs builds from

Design Invariants#

To maintain consistency across all our documentation sites, we follow these invariants:

  1. Unified Configuration
  2. All documentation sites reuse the same mkdocs.yml template
  3. Only site_name, site_url, and site-specific settings change
  4. Blogs add the blog plugin but keep the same base structure

  5. Standardized Workflows

  6. Only two GitHub workflow templates:
    • Documents workflow: For standard documentation (with preprocessing)
    • Blog workflow: For blog posts (no preprocessing needed)
  7. Same logic with small variations for S3 vs GitHub Pages

  8. Consistent Structure

  9. All sites follow the same directory layout
  10. Assets and styles in predictable locations
  11. Preprocessing always outputs to tmp.mkdocs/

  12. Shared Assets

  13. Logo, favicon, and CSS should be symlinked from canonical sources
  14. This ensures consistency and single source of truth
  15. Changes propagate to all sites automatically

Canonical Assets and CSS#

To ensure consistent branding and styling across all documentation sites, we maintain canonical versions of shared assets.

Source of Truth#

The canonical assets are located in the helpers repository:

helpers_root/docs/mkdocs/assets/logo.png
helpers_root/docs/mkdocs/assets/favicon.ico
helpers_root/docs/mkdocs/styles/styles.css

  • When creating a new documentation site, symlink rather than copy these files:

Benefits of symlinking:

  • Single source of truth for branding
  • Updates to logo/favicon/styles propagate automatically
  • No duplicate files to maintain
  • Consistent appearance across all sites

Verify symlinks:

ls -la docs/assets/
ls -la docs/styles/

You should see symlinks pointing to the helpers repository.

How to Publish Documentation#

Preview Locally#

Before publishing, always preview your documentation locally to ensure it renders correctly.

Step 1: Run preprocessing

Navigate to your repository root and run the preprocessing script:

cd ~/src/your_repo

# Run Preprocessing.
python helpers_root/docs/mkdocs/preprocess_mkdocs.py \
    --input_dir docs \
    --output_dir tmp.mkdocs \
    -v INFO

Step 2: Activate the MkDocs environment

source "$HOME/src/venv/mkdocs/bin/activate"

Step 3: Navigate to your docs directory

cd your_docs_directory  # e.g., docs_mkdocs/ or the directory with mkdocs.yml

Step 4: Start the local server

mkdocs serve

Step 5: Open in browser

  • The terminal will display the URL (typically http://127.0.0.1:8000)
  • Open this URL in your browser
  • The server supports live reload - changes will auto-refresh

Step 6: Stop the server

Press Ctrl+C when done previewing

Publish to Custom Domain (S3) (Instead of Gh-Pages)#

Prerequisites:

  • S3 bucket configured for static hosting
  • AWS credentials configured in GitHub repository secrets
  • CloudFront distribution (optional but recommended)

Step 1: Set up GitHub Actions workflow

Create and .github/workflows/publish_docs.yml:

name: Publish MkDocs

on:
    push:
        branches:
            - master
        paths:
            - docs/**
    workflow_dispatch:

permissions:
    id-token: write
    contents: read

jobs:
    deploy:
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v4
                with:
                    submodules: recursive # If using helpers as submodule.
            - name: Setup Python
                uses: actions/setup-python@v5
                with:
                    python-version: 3.x
            - name: Install MkDocs
                run: pip install mkdocs mkdocs-material
            - name: Run preprocessing
                run: |
                    python helpers_root/docs/mkdocs/preprocess_mkdocs.py \
                        --input_dir docs \
                        --output_dir tmp.mkdocs \
                        -v INFO
            - name: Build MkDocs
                run: mkdocs build
                working-directory: ./docs_mkdocs # Adjust to your structure.
            - name: Configure AWS credentials
                uses: aws-actions/configure-aws-credentials@v1
                with:
                    role-to-assume: ${{ vars.GH_ACTION_AWS_ROLE_ARN }}
                    role-session-name: ${{ vars.GH_ACTION_AWS_SESSION_NAME }}
                    aws-region: ${{ vars.CSFY_AWS_DEFAULT_REGION }}
            - name: Publish to S3
                run: |
                    aws s3 sync ./docs_mkdocs/site s3://your-bucket-name --delete

The workflow will automatically run on push to master! Example: Csfy Repo docs Git Action

Publish to Github Pages#

Prerequisites:

  • GitHub Pages enabled in repository settings
  • gh-pages branch will be created automatically

Step 1: Set up GitHub Actions workflow

Create .github/workflows/publish_mkdocs.yml:

name: Publish MkDocs

on:
    push:
        branches:
            - master
        paths:
            - docs/**
    workflow_dispatch:

permissions:
    contents: write

jobs:
    deploy:
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v4
                with:
                    submodules: recursive # If using helpers as submodule.
            - name: Configure Git Credentials
                run: |
                    git config user.name github-actions[bot]
                    git config user.email 41898282+github-actions[bot]@users.noreply.github.com
            - uses: actions/setup-python@v5
                with:
                    python-version: 3.x
            - run: pip install mkdocs mkdocs-material
            - name: Update PYTHONPATH
                run: |
                    echo "PYTHONPATH=${{ github.workspace }}:${{ github.workspace }}/helpers_root" >> $GITHUB_ENV
            - name: Preprocess MkDocs
                working-directory: ./docs/mkdocs # Adjust to your structure.
                run: |
                    python ../../helpers_root/docs/mkdocs/preprocess_mkdocs.py \
                        --input_dir docs \
                        --output_dir tmp.mkdocs
            - run: mkdocs gh-deploy --force
                working-directory: ./docs/mkdocs

Step 2: Enable GitHub Pages

  1. Go to repository Settings → Pages
  2. Source: Deploy from a branch
  3. Branch: gh-pages / / (root)
  4. Click Save

Step 3: Commit and push

git add .github/workflows/publish_mkdocs.yml
git commit -m "Add MkDocs GitHub Pages workflow"
git push origin master

Step 4: Access your site

After the workflow completes:

  • Your site will be available at: https://<org>.github.io/<repo>/
  • Example: https://causify-ai.github.io/helpers/

Mkdocs Configuration#

Example Mkdocs.Yml#

Here's a standard mkdocs.yml template used across all Causify documentation:

site_name: Your Site Name
# Site_Url: Https://Yourdomain.Org/Yoursite # Optional: for Absolute Urls.

theme:
    name: material
    palette:
        primary: black
        accent: cyan
    logo: assets/logo.png
    favicon: assets/favicon.ico
    features:
        # - navigation.tabs
        # - navigation.top
        - content.action.edit  # Shows "Edit this page" link.

# CRITICAL: Docs_Dir Must Point to Preprocessed Content.
docs_dir: tmp.mkdocs

# Helps Render Images and Other Assets Correctly.
use_directory_urls: false

# Plugins - Search Is Enabled by Default, but Must Be Explicit If You Add Others.
plugins:
    - search

# Markdown Extensions for Enhanced Functionality.
markdown_extensions:
    - toc:
            permalink: "#"
            baselevel: 2
            separator: "_"
    - pymdownx.superfences:
            custom_fences:
                - name: mermaid
                    class: mermaid
                    format: !!python/name:pymdownx.superfences.fence_code_format

# Custom CSS.
extra_css:
    - styles/styles.css

Example at: Helpers repo mkdocs

Key Configuration Options#

site_name

  • Required: The name of your documentation site
  • Appears in the browser title and site header
  • Example: "Helpers Documentation", "Causify Docs"

site_url

  • Optional but recommended for SEO and absolute URLs
  • Format: https://yourdomain.com/path
  • Not needed for GitHub Pages (auto-detected)

theme

  • We use Material theme for all documentation
  • Colors: primary: black, accent: cyan (Causify brand colors)
  • Logo and favicon paths relative to docs_dir

docs_dir

  • CRITICAL: Must be tmp.mkdocs (preprocessed content)
  • Never point directly to docs/ - preprocessing is required

use_directory_urls: false

  • Ensures clean URLs work with S3 static hosting
  • Pages are page.html instead of page/index.html
  • Required for S3/CloudFront setup

plugins

  • search: Enables full-text search (include explicitly if adding others)
  • For blogs, add the blog plugin here

markdown_extensions

  • Table of contents with permalink support
  • pymdownx.superfences: Code blocks with syntax highlighting and mermaid diagrams

extra_css

  • Path to custom stylesheet (relative to docs_dir)
  • Should point to styles/styles.css (symlinked from canonical)

Preprocessing#

What Preprocessing Does#

The preprocessing script (preprocess_mkdocs.py) transforms raw markdown files before MkDocs builds them. It performs:

  1. Removes table of contents blocks
  2. Strips content between markers
  3. MkDocs generates its own navigation

  4. Dedents Python code blocks

  5. Ensures code is properly aligned
  6. Fixes indentation issues that break rendering

  7. Standardizes indentation

  8. Converts 2-space indentation to 4 spaces
  9. Maintains consistent code formatting

  10. Processes markdown syntax

  11. Handles mermaid diagrams
  12. Processes PlantUML blocks
  13. Other markdown transformations via hmkdocs helpers

  14. Copies and processes directory structure

  15. Creates tmp.mkdocs/ with all processed files
  16. Preserves directory structure
  17. Copies assets and styles

Running Preprocessing Manually#

Basic usage:

python helpers_root/docs/mkdocs/preprocess_mkdocs.py \
    --input_dir docs \
    --output_dir tmp.mkdocs \
    -v INFO

Examples#

Causify Documentation (S3 + Custom Domain):

Helpers Documentation (GitHub Pages):

Causify Blog (S3 + Custom Domain):