Migration Express
Migrate your existing static site to Bengal while preserving URLs.
Coming from Hugo, Jekyll, or Gatsby? This track shows you how to migrate content, adapt frontmatter, and preserve your URLs.
Tip
Duration: ~60 min | Prerequisite: Existing static site to migrate
Key Capabilities
What Bengal does
Key Capabilities
Bengal is a static site generator that produces HTML, CSS, and JavaScript from Markdown content and Kida templates.
What Bengal Does
Content & Authoring
- MyST Markdown — Directives, admonitions, cross-references, tabs, cards
- 50+ Built-in Directives — Code tabs, dropdowns, galleries, video embeds, versioning badges
- Content Collections — Type-safe frontmatter validation with dataclass or Pydantic schemas
- Mixed Content Types — Docs, blog, landing pages, changelogs in one site
Performance
- Kida Templates — 1.81x faster than Jinja2 under concurrent workloads
- Incremental Builds — 35-80ms rebuilds for single-page edits
- Free-Threading — True parallelism on Python 3.14+ (no GIL contention)
- Parallel Rendering — 2-4x speedup on multi-core systems
Developer Experience
- Auto-generated API Docs — From Python source, CLI tools, and OpenAPI specs
- Image Processing — Resize, crop, format conversion (WebP/AVIF), srcset generation
- Zero-Config Deploy — Auto-detects GitHub Pages, Netlify, Vercel
- Theme System — Install themes from PyPI, swizzle templates, 1,100+ CSS tokens
Quality & Validation
- Health Checks — Broken links, missing images, frontmatter validation
- Auto-Fix —
bengal fixrepairs common issues automatically - Site Analysis — Graph visualization, orphan detection, content metrics
Technical Details
Seealso
Section 2: Page Not Found
Could not find page:docs/tutorials/onboarding/_index
Section 3: Page Not Found
Could not find page:docs/tutorials/onboarding/from-hugo
Section 4: Page Not Found
Could not find page:docs/tutorials/onboarding/from-sphinx
Section 5: Page Not Found
Could not find page:docs/tutorials/onboarding/from-docusaurus
Content Organization
Pages, sections, and bundles explained
How Content is Organized
Your folder structure becomes your site structure. No configuration required.
The Three Content Types
A single.mdfile → a single HTML page.
content/
└── about.md → /about/
Use for: standalone pages like About, Contact, Privacy Policy.
A folder with_index.md→ a list page with children.
content/
└── blog/
├── _index.md → /blog/ (list page)
├── post-1.md → /blog/post-1/
└── post-2.md → /blog/post-2/
Use for: blog posts, documentation chapters, any collection.
A folder withindex.md→ a page with co-located assets.
content/
└── gallery/
├── index.md → /gallery/
├── photo-1.jpg (co-located asset)
└── photo-2.jpg (co-located asset)
Use for: pages with images, data files, or other assets that belong together.
Quick Reference
| Pattern | File | Creates | Assets |
|---|---|---|---|
| Page | name.md |
Single page | Usestatic/ |
| Section | name/_index.md |
List + children | Usestatic/ |
| Bundle | name/index.md |
Single page | Co-located |
Tip
Key difference:_index.md creates a section (with children). index.mdcreates a bundle (with assets). The underscore matters!
Advanced: Nesting and Cascades
Sections can nest to any depth:
docs/
├── _index.md
├── getting-started/
│ ├── _index.md
│ └── installation.md
└── advanced/
├── _index.md
└── plugins.md
Configuration cascades from parent to children:
---
title: Docs
cascade:
type: doc
toc: true
---
All pages under docs/ inherit type: doc and toc: trueunless they override it.
Seealso
- Component Model — Understanding type, variant, and props
- Frontmatter Reference — All frontmatter fields
- Menu Configuration — Navigation menus
Frontmatter Reference
Complete reference for all frontmatter fields
Frontmatter Reference
Complete reference for all frontmatter fields available in Bengal pages.
Required Fields
| Field | Type | Description |
|---|---|---|
title |
string | Page title, used in navigation and<title>tag |
Common Fields
| Field | Type | Default | Description |
|---|---|---|---|
description |
string | — | Page description for SEO and previews |
date |
datetime | file mtime | Publication date |
draft |
boolean | false |
Iftrue, page is excluded from production builds |
weight |
integer | — | Sort order (lower = first). Pages without weight sort last. |
slug |
string | filename | URL slug override |
url |
string | — | Complete URL path override |
aliases |
list | [] |
Additional URLs that redirect to this page |
lang |
string | site default | Language code for i18n (e.g.,en, fr) |
Taxonomy Fields
| Field | Type | Description |
|---|---|---|
tags |
list | Tags for categorization (generates tag pages) |
category |
string | Single category for grouping (generates category pages) |
keywords |
list | SEO keywords (metadata only, no pages generated) |
author |
string/object | Page author (see Author Patterns below) |
Note
Onlytags and category generate taxonomy pages by default. Use author(singular) for author attribution.
Author Patterns
Bengal supports multiple author patterns for flexibility:
Simple string (reference to data registry):
author: lbliii
Nested object (inline):
author:
name: Lawrence Lane
github: lbliii
bio: Technical writer and developer
Multiple authors (list of strings or objects):
authors:
- lbliii
- name: Jane Smith
github: janesmith
Flat author fields (legacy pattern):
author: Lawrence Lane
author_avatar: /images/lawrence.jpg
author_title: Senior Developer
author_bio: Technical writer and developer
author_links:
- text: GitHub
url: https://github.com/lbliii
Author Data Registry
Define authors once indata/authors.yamland reference by key:
# data/authors.yaml
lbliii:
name: Lawrence Lane
github: lbliii
bio: Technical writer and developer
avatar: /images/lawrence.jpg
Then reference in frontmatter:
author: lbliii
Access in templates:
{% let author_info = site.data.authors[page.metadata.author] %}
{{ author_info.name }} — {{ author_info.bio }}
Component Model Fields
Bengal uses a Component Model where every page has three aspects: identity (type), appearance (variant), and data (props).
| Field | Type | Default | Description |
|---|---|---|---|
type |
string | — | Content type for sorting and template selection (e.g.,doc, blog, page). Inherits from section cascade if not set. |
variant |
string | — | Visual presentation variant (e.g.,editorial, magazine, wide, overview) |
layout |
string | — | Legacy field, normalized tovariant. Use variantinstead. |
template |
string | — | Explicit template path override (e.g.,blog/single.html) |
nav_title |
string | title |
Short title for navigation menus and sidebar |
SEO Fields
| Field | Type | Description |
|---|---|---|
canonical |
string | Canonical URL for duplicate content |
noindex |
boolean | Iftrue, adds noindexmeta tag |
og_image |
string | Open Graph image path |
og_type |
string | Open Graph type (article, website, etc.) |
Navigation Fields
| Field | Type | Description |
|---|---|---|
menu |
object | Menu placement configuration |
nav_title |
string | Short title for navigation (falls back totitle) |
parent |
string | Parent page for breadcrumbs |
Advanced Fields
| Field | Type | Description |
|---|---|---|
cascade |
object | Values to cascade to child pages |
outputs |
list | Output formats (html, rss, json) |
resources |
list | Page bundle resource metadata |
Custom Fields (Props)
Any fields not part of Bengal's standard frontmatter are automatically available as custom props. Add them at the top level of your frontmatter.
Standard fields (extracted to PageCore):
title,description,date,draft,weight,slug,url,aliases,langtags,categories,keywords,authors,categorytype,variant,layout,templatecanonical,noindex,og_image,og_typemenu,nav_title,parentcascade,outputs,resources,toc
Custom fields (Component Model props):
- Any field not listed above goes into
page.props - Access in templates via
page.params(includes all frontmatter) orpage.props(custom fields only)
Example
---
title: My Page
description: Page description
weight: 10
type: doc
icon: code
card_color: blue
custom_setting: value
---
Access custom fields in templates:
{# page.params includes all frontmatter (standard + custom) #}
{{ page.params.icon }}
{{ page.params.get('card_color', 'default') }}
{# page.props contains only custom fields #}
{{ page.props.icon }}
Note: The props: key is only used in skeleton manifests (bengal project skeleton apply). For regular markdown files, use flat frontmatter (all fields at top level).
Example
---
title: Getting Started with Bengal
description: Learn how to install and configure Bengal for your first site
date: 2025-01-15
draft: false
weight: 10
tags: [tutorial, beginner]
categories: [Getting Started]
authors: [jane-doe]
type: tutorial
variant: wide
cascade:
type: doc
difficulty: beginner
time_estimate: 15 minutes
---
In this example:
- Standard fields (
title,date,weight, etc.) are extracted to PageCore difficultyandtime_estimateare custom props accessible viapage.paramscascadepropagatestype: docto all child pages
Cascade Configuration
Thecascadefield applies values to all descendant pages:
---
title: Documentation
cascade:
type: doc
variant: docs
draft: false
---
All pages under this section inherit these values unless they override them. Page-level values always take precedence over cascaded values.
Configuration
Configuring Bengal with bengal.toml
Configuration
Control Bengal's behavior throughbengal.tomland environment-specific settings.
Configuration Methods
Bengal loads configuration from either theconfig/ directory (preferred) OR bengal.toml (legacy/simple). If config/ exists, bengal.tomlis ignored.
Overrides apply in order: Base Config → Environment Overrides → CLI Flags.
Quick Start
# bengal.toml
[site]
title = "My Site"
baseurl = "https://example.com"
language = "en"
[build]
output_dir = "public"
[theme]
name = "default"
Configuration Patterns
Best for small sites:
# bengal.toml - everything in one place
[site]
title = "My Blog"
[build]
output_dir = "public"
[theme]
name = "default"
Best for larger sites:
config/
├── _default/
│ ├── site.yaml
│ ├── build.yaml
│ └── theme.yaml
└── environments/
├── production.yaml
└── staging.yaml
Environment Overrides
Run with different settings per environment:
bengal build --environment production
# config/environments/production.yaml
site:
baseurl: "https://example.com"
build:
minify_html: true
strict_mode: true
assets:
fingerprint: true
Tip
Best practice: Keep development settings inbengal.toml, add production overrides in config/environments/production.yaml.
Build Options Reference
Key[build]configuration options:
| Option | Type | Default | Description |
|---|---|---|---|
output_dir |
string | "public" |
Directory for generated files |
minify_html |
bool | true |
Minify HTML output |
validate_templates |
bool | false |
Proactive template syntax validation |
validate_build |
bool | true |
Post-build validation checks |
validate_links |
bool | true |
Check for broken internal links |
strict_mode |
bool | false |
Fail build on any error or warning |
fast_mode |
bool | false |
Enable maximum performance optimizations |
Note
Incremental builds are automatic. First build is full (creates cache), subsequent builds only rebuild changed content. Use--no-incrementalCLI flag for debugging or CI clean builds.
Asset Options
Configure asset processing in the[assets]section:
| Option | Type | Default | Description |
|---|---|---|---|
minify |
bool | true |
Minify CSS/JS assets |
optimize |
bool | true |
Optimize images |
fingerprint |
bool | true |
Add content hash to asset URLs |
[assets]
minify = true
optimize = true
fingerprint = true
Template Validation
Enablevalidate_templatesto catch template syntax errors early during builds:
[build]
validate_templates = true
When enabled, Bengal validates all templates (HTML/XML) in your template directories before rendering. This provides early feedback on syntax errors, even for templates that might not be used by every page.
Enable template validation during development for immediate feedback:
[build]
validate_templates = true
Combine with strict mode in CI pipelines to fail builds on template errors:
[build]
validate_templates = true
strict_mode = true
When to enable:
- During active theme development
- In CI/CD pipelines
- When debugging template issues
What it catches:
- Template syntax errors (unclosed tags, invalid filters) in Kida and Jinja2
- Unknown filter names
- Template assertion errors
Note
Template validation adds a small overhead to build time. For large sites, consider enabling it only in development and CI environments.