AutoSite: a near-zero-config, Markdown-based static site generator

Static site generators tend to grow heavy fast: complex configuration schemas, sprawling theme layers, and plugin systems that force you to memorize dozens of toggles before you can publish “Hello, world.” AutoSite goes in the opposite direction. It is a minimalist, Markdown-driven generator: a small set of primitives, a single YAML file for configuration, and sane defaults that yield a clean, responsive site out of the box.  

Project on GitHub

Design goals

AutoSite pursues four explicit goals:

  • Zero configuration by default. A new site can be built with a single command, using only config.yaml.  
  • Markdown as the source of truth. Pages and collections are .md files. Titles and structure come from headings and filenames, not from a metadata DSL.  
  • Minimal, modern UX. A lightweight CSS/JS bundle delivers responsive navigation, smooth animations, and code highlighting.  
  • Predictable ordering and clean URLs. Filenames can be prefixed with numbers for sorting, while generated URLs remain clean.  

Build pipeline

The entry point is the CLI script gen.py, which takes three parameters—--config, --output, and --paginate-by—and then calls generate_site(...).

# gen.py

if __name__ == '__main__':

    import argparse

    parser = argparse.ArgumentParser(description='Generate a static site from markdown.')

    parser.add_argument('--config', default='config.yaml')

    parser.add_argument('--output', default='site')

    parser.add_argument('--paginate-by', type=int, default=10)

    args = parser.parse_args()

    generate_site(args.config, args.output, args.paginate_by)

Inside site_generator.py, the SiteGenerator orchestrates four stages:

  1. Load configuration (SiteConfig)  
  2. Generate assets (AssetManager)  
  3. Build navigation (NavigationBuilder)  
  4. Render homepage and pages (PageGenerator)  
class SiteGenerator:

    def generate(self, paginate_by: int = 10) -> None:

        print(f"Generating website: {self.config.site_title}")

        self.asset_manager.generate_all_assets(self.config.theme)

        nav = self.nav_builder.build_navigation()

        page_generator = PageGenerator(..., nav=nav)

        page_generator.generate_homepage(self.config.homepage)

        for page in self.config.pages:

            page_generator.generate_page(page, paginate_by)

Configuration

Configuration is loaded by SiteConfig from config.yaml. It provides defaults for missing fields and normalizes paths and URLs.

title: "My Awesome Site"
base_url: "/my-site"
homepage: "content/home.md"


theme:
  font_family: "'Inter', sans-serif"
  primary_color: "#3b82f6"
  contrast_color: "#1e40af"


pages:

  - title: "About"
    path: "content/about.md"

  - title: "Blog"
    path: "content/blog"

Key fields:

  • title: site title  
  • base_url: normalized to end with /  
  • homepage: markdown file for the index page  
  • pages: list of internal or external links  
  • theme: font and colors  
  • assets.source_dir: source dir for static files  

Content conventions

The utility module defines simple but powerful helpers:

  • slugify(value): make URL-safe slugs  
  • extract_first_h1/h2: take titles from markdown headings  
  • extract_order_number: read numeric prefix from filenames (e.g. 10-intro.md → 10)  
  • remove_order_prefix: strip prefix for clean URLs and titles  

This system allows deterministic ordering (1-intro.md, 2-setup.md, …) without polluting URLs (/blog/intro.html instead of /blog/1-intro.html).

Templates

The HTML is defined by three Jinja-style templates:

  • BASE_TEMPLATE: HTML skeleton, SEO meta, Open Graph tags, nav, and assets (CSS, JS, highlight.js).  
  • LIST_TEMPLATE: collection pages with pagination.  
  • PAGE_TEMPLATE: single markdown pages.  

This makes it trivial to theme or extend: just edit templates in place.

Assets

Styling and interactivity live in two string templates:

  • CSS_TEMPLATE: defines variables (--primary-color, --font-family) and styles a sticky header, nav, pagination, and animations.  
  • JS_TEMPLATE: pure DOM API, handling hamburger toggle, smooth scrolling, fade-in animations, and header hide/show on scroll.  

Both are written into the output directory during build.

Navigation and pages

Navigation is generated from the pages list. Each item may be:

  • An external link (left untouched, just added to nav).  
  • A markdown page (rendered to HTML).  
  • A directory of markdown files (rendered with LIST_TEMPLATE, ordered numerically with pagination).  

SEO and runtime polish

Every page includes:

  • SEO meta: description, robots  
  • Open Graph + Twitter cards  
  • Code highlighting via highlight.js  
  • Responsive header and nav, animated with CSS/JS  

This is enough for a small blog or documentation site without extra plugins.

AutoSite shows how far you can go with a small, principled design: Markdown as content, one YAML config, a handful of templates, and minimal but modern UX. It favors readability and explicitness, making it easy to adopt, extend, and explain. If you’re tired of heavyweight static site stacks, AutoSite is a refreshing alternative: powerful enough for a blog or docs site, yet simple enough to teach in ten minutes.

Project on GitHub


You'll only receive email when they publish something new.

More from GSLF
All posts