Bengal vs Pelican vs MkDocs — Python Static Site Generators Compared

Head-to-head comparison of Bengal, Pelican, and MkDocs — build speed, object models, batteries included, templating, incremental builds, and when to choose each.

Three Python static site generators. Three different design philosophies.


TL;DR

Bengal Pelican MkDocs
Best for Docs, blogs, product sites Blogs, content-heavy Documentation
Object model Generic (Page, Section, Asset) Blog-centric (Article, Author, Tag) Docs-centric (nav, sections)
Built-in Sitemap, RSS, search, social cards RSS; sitemap/search via plugins Search, sitemap
Templating Kida (Jinja2-like) Jinja2 Jinja2 (Material, etc.)
Markdown Patitas (MyST) Markdown, reST Markdown
Parallel builds Yes (3.14t) No No
Incremental Yes (sub-second) Limited Limited
Python 3.14+ 3.8+ 3.8+

Build speed and parallelism

Bengal Pelican / MkDocs
Parallel rendering Yes (3.14t, ThreadPoolExecutor) No
Large sites Parallel, scales with workers Linear with page count
Incremental Yes — affected pages only Limited / none
Single-page edit Sub-second Full rebuild

Bengal is built for free-threaded Python. Pelican and MkDocs run on traditional Python; build times scale roughly linearly.


Content model

Bengal Pelican MkDocs
Markdown Patitas (MyST) Markdown, reST Markdown + Material
Directives Callouts, admonitions, figures
Structure Sections + _index.md Similar + index.md mkdocs.yml defines nav

Object models

Each SSG has its own object model — the types it uses to represent content and structure.

Bengal Pelican MkDocs
Core types Site, Page, Section, Asset, Theme Article, Page, Category, Tag, Author Docs, nav, sections
Content types Generic pages (blog, docs, product) Articles vs pages; blog-centric Documentation
Taxonomy Optional (via frontmatter) Built-in categories, tags, authors Nav hierarchy
Hierarchy Sections (directories) Categories, tags Nav tree
Bengal Pelican MkDocs
Philosophy Content-agnostic Blog-centric Docs-first
Template vars page (all content) article (posts), page (static) docs, nav
Content type One Page type Article vs Page Nav hierarchy
flowchart TB subgraph Bengal["Bengal — generic"] B_Site[Site] B_Page[Page] B_Section[Section] B_Asset[Asset] B_Site --> B_Page B_Site --> B_Section B_Site --> B_Asset end subgraph Pelican["Pelican — blog-centric"] P_Article[Article] P_Page[Page] P_Author[Author] P_Cat[Category] P_Tag[Tag] P_Article --> P_Author P_Article --> P_Cat P_Article --> P_Tag end subgraph MkDocs["MkDocs — docs-centric"] M_Nav[Nav] M_Docs[Docs] M_Sections[Sections] M_Nav --> M_Docs M_Nav --> M_Sections end

Batteries included

All three ship with useful defaults, but the kind of batteries differs.

Bengal Pelican MkDocs
Sitemap Built-in (XML) Plugin Built-in (XML)
RSS/Atom Built-in Built-in No (docs-only)
Search Built-in (Lunr, index.json) Plugin Built-in (Lunr)
404, robots.txt Built-in Theme-dependent Built-in
Social cards, Open Graph Built-in Theme-dependent Theme-dependent
Output formats JSON, LLM txt, index.json

Bengal — built-in (no plugins):

  • Sitemap, RSS, search indexes (Lunr, index.json)
  • Canonical URLs, Open Graph, Twitter cards
  • Machine outputs: index.json, llm-full.txt

MkDocs — built-in for docs:

  • Search (Lunr), sitemap
  • No RSS (docs-only)
  • Social metadata: theme-dependent (e.g. Material)

Pelican — built-in vs plugins:

  • Built-in: RSS/Atom feeds
  • Plugins: sitemap, search
  • Strength: plugin ecosystem; you add what you need
flowchart LR subgraph Bengal["Bengal build"] B1[Content] --> B2[Parallel render] B2 --> B3[Sitemap] B2 --> B4[RSS] B2 --> B5[Search index] B2 --> B6[Social cards] end subgraph Pelican["Pelican build"] P1[Content] --> P2[Sequential render] P2 --> P3[RSS] P2 --> P4[Plugin: sitemap] P2 --> P5[Plugin: search] end subgraph MkDocs["MkDocs build"] M1[Content] --> M2[Sequential render] M2 --> M3[Search] M2 --> M4[Sitemap] end

Templating

Bengal Pelican MkDocs
Engine Kida Jinja2 Jinja2 (Material, etc.)
Syntax {{ variable }}, {% for %}, {% block %} Same Same
Extras Static analysis (required_context)
Free-threading Yes No No

Incremental builds

Bengal Pelican MkDocs
On file change Rebuild affected only Full rebuild Full rebuild
Cache Zstandard, provenance-based --ignore-cache only None
Typical time Sub-second Full rebuild Full rebuild
flowchart TB subgraph Bengal["Bengal — incremental"] B_Change[One file changes] B_Change --> B_Hash[Content hash] B_Hash --> B_Dep[Rebuild affected only] B_Dep --> B_Out[Sub-second] end subgraph Pelican["Pelican / MkDocs"] P_Change[One file changes] P_Change --> P_Full[Full rebuild] P_Full --> P_Out[Seconds to minutes] end

Same page, three templates

A production-style layout with null coalescing and optional metadata. Kida supports ?. (optional chaining) and ?? (null coalescing); Jinja2 uses | default() and defensive conditionals.

{% extends "base.html" %}
{% block title %}{{ page.title | default(site.title) }}{% end %}
{% block content %}
<article>
  <h1>{{ page.title ?? 'Untitled' }}</h1>
  {% if page.date %}
  <time>{{ page.date | dateformat("%Y-%m-%d") }}</time>
  {% end %}
  {{ page.content | safe }}
  {% set links = params?.quick_links ?? [] %}
  {% for link in links %}
  <a href="{{ link?.href ?? link?.url ?? '#' }}">{{ link?.title ?? 'Link' }}</a>
  {% end %}
</article>
{% end %}
{% extends "base.html" %}
{% block title %}{{ article.title | default(site.title) }}{% endblock %}
{% block content %}
<article>
  <h1>{{ article.title | default('Untitled') }}</h1>
  {% if article.date %}
  <time>{{ article.date.strftime('%Y-%m-%d') }}</time>
  {% endif %}
  {{ article.content }}
  {% set links = (article.quick_links if article else []) or [] %}
  {% for link in links %}
  <a href="{{ (link.href or link.url) or '#' }}">{{ link.title | default('Link') }}</a>
  {% endfor %}
</article>
{% endblock %}
# Page Title

Page content in Markdown. Material theme handles layout.
Nav comes from mkdocs.yml — no template inheritance.
No optional chaining or null coalescing in templates.
Kida Jinja2
Null coalescing ?? | default()
Optional chaining ?. if x else y
Block end {% end %} (all blocks) {% endblock %}, {% endfor %}, {% endif %}
Variable names page page or article

Where each shines (and stumbles)

Shines: Parallel builds on 3.14t. Sub-second incremental rebuilds. Provenance-based cache. MyST directives (callouts, tabs, figures). Static analysis for block caching.

Stumbles: Newer ecosystem. Fewer plugins than Pelican. Python 3.14+ only. Kida syntax uses {% end %} instead of {% endblock %} — small migration cost from Jinja2.

Shines: Mature (since 2010). Huge plugin ecosystem. reStructuredText support. Themes and community. Works on Python 3.8+.

Stumbles: No parallel rendering. No true incremental builds. Full rebuild every time. GIL-bound for CPU work.

Shines: Simple config. Material theme is polished. Great for docs. Fast to get started. Nav in YAML, not templates.

Stumbles: Docs-only focus. No blog primitives (tags, dates, feeds) without plugins. Full rebuild. Not designed for product sites or complex layouts.

Shines Stumbles
Bengal Parallel builds, sub-second incremental, MyST directives, static analysis Newer, fewer plugins, 3.14+ only
Pelican Mature (2010), huge plugins, reST No parallel, full rebuild, GIL-bound
MkDocs Simple config, Material theme, fast start Docs-only, no blog primitives, full rebuild

Config comparison

# bengal.yaml
site:
  title: My Site
  base_url: https://example.com
# pelicanconf.py
AUTHOR = "You"
SITENAME = "My Site"
SITEURL = "https://example.com"
# mkdocs.yml
site_name: My Site
site_url: https://example.com
Bengal Pelican MkDocs
Config format YAML Python YAML
Tradeoff Declarative Flexible, in code Declarative

When to choose Bengal

  • You have hundreds of pages and care about build speed
  • You want incremental rebuilds for a fast editing loop
  • You're on Python 3.14 and want to use free-threading
  • You need docs, blog, or product site with sitemaps, feeds, and search indexes

See Best Python Static Site Generators for 2026 for the full roundup.


When to choose Pelican or MkDocs instead

Use case Choice Why
Mature ecosystem, lots of plugins Pelican Since 2010, strong community
Docs only, simple setup MkDocs Opinionated, excels at docs
Blogs or product sites Pelican or Bengal MkDocs not designed for complex layouts