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

1

Comparison

How Bengal compares to other static site generators

Comparison

Bengal Hugo MkDocs Jekyll
Language Python Go Python Ruby
Templates Jinja2 Go Templates Jinja2 Liquid
Speed ~200 pages/s ~10,000 pages/s ~100 pages/s ~50 pages/s
Mixed content Yes Yes No (docs only) Yes
Incremental builds Yes Yes No No

What Bengal Does

  • Jinja2 templates — Same templating as Flask/Django
  • Incremental builds — Rebuild only changed files
  • Mixed content — Docs, blog, landing pages in one site
  • Auto-generated docs — API docs from Python source
  • Asset pipeline — Fingerprinting and minification
  • MyST Markdown — Directives, admonitions, cross-references

Seealso

2

Migrate from Hugo

Migrate your site from Hugo, Jekyll, Gatsby, or other static site generators to Bengal

Migrate Content from Other SSGs

Migrate your existing static site to Bengal. Whether you're coming from Hugo, Jekyll, Gatsby, or another SSG, these steps help you preserve your content and URLs.

When to Use This Guide

  • You have an existing site built with another static site generator
  • You want to preserve your content structure and URLs
  • You need to convert frontmatter formats
  • You want to maintain your site's SEO and link structure

Prerequisites

Before You Begin

  • Bengal installed
  • Access to your existing site's source files
  • Basic knowledge of Markdown and YAML/TOML

Steps

  1. 1

    Create Your Bengal Site

    Initialize a fresh Bengal project as your migration destination.

    Start by creating a new Bengal site:

    1
    2
    bengal new site mysite
    cd mysite
    

    Choose Blank preset if you're migrating existing content, or select a preset that matches your site type.

  2. 2

    Understand Content Structure Differences

    Learn how Bengal's file-system routing compares to your current SSG.

    File Organization

    Bengal uses file-system routing where thecontent/directory structure directly maps to URLs:

    SSG Content Location Bengal Equivalent
    Hugo content/ content/
    Jekyll _posts/,_pages/ content/blog/,content/
    Gatsby src/pages/ content/
    Next.js pages/ content/

    Index Files

    Bengal distinguishes between section and page index files:

    • _index.md - Creates a section (folder that can contain pages)
    • index.md - Creates a page in its own folder

    This is different from Hugo's_index.md(always a section) and Jekyll'sindex.html(always a page).

  3. 3

    Convert Frontmatter

    Adapt your frontmatter fields to Bengal's conventions.

    From Hugo

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # Hugo frontmatter
    ---
    title: "My Post"
    date: 2023-10-25
    draft: false
    tags: [python, web]
    categories: [tutorial]
    slug: my-post
    weight: 10
    ---
    
    # Converted to Bengal
    ---
    title: My Post
    date: 2023-10-25
    draft: false
    tags: [python, web]
    category: tutorial  # Note: singular, not plural
    slug: my-post
    weight: 10
    ---
    

    Key differences:

    • categories(plural) →category(singular) in Bengal
    • Remove quotes from simple string values
    • Date format remains the same (ISO format)

    From Jekyll

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # Jekyll frontmatter
    ---
    layout: post
    title: "My Post"
    date: 2023-10-25 14:30:00 +0000
    categories: [tutorial, python]
    tags: [web]
    published: true
    ---
    
    # Converted to Bengal
    ---
    type: post  # layout → type
    title: My Post
    date: 2023-10-25T14:30:00Z  # Convert to ISO format
    category: tutorial  # Use first category
    tags: [web]
    draft: false  # published: true → draft: false
    ---
    

    Key differences:

    • layouttypein Bengal (see Component Model: Type)
    • published: truedraft: false
    • categoriescategory(use first category)
    • Date format: Convert to ISO format

    From Gatsby/MDX

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    # Gatsby frontmatter
    ---
    title: "My Post"
    date: "2023-10-25"
    author: "John Doe"
    tags: ["python", "web"]
    featured: true
    ---
    
    # Converted to Bengal
    ---
    title: My Post
    date: 2023-10-25
    author: John Doe
    tags: [python, web]
    # featured can be stored in params or custom frontmatter
    ---
    
  4. 4

    Migrate Content Files

    Copy and convert your existing content to Bengal format.

    Automated Migration Script

    Create a simple Python script to help with bulk conversion:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    #!/usr/bin/env python3
    """Convert Hugo/Jekyll content to Bengal format."""
    
    import re
    from pathlib import Path
    
    def convert_frontmatter(content: str, source_format: str = "hugo") -> str:
        """Convert frontmatter from source format to Bengal."""
        # Extract frontmatter
        frontmatter_match = re.match(r'^---\n(.*?)\n---\n', content, re.DOTALL)
        if not frontmatter_match:
            return content
    
        frontmatter = frontmatter_match.group(1)
        body = content[frontmatter_match.end():]
    
        # Convert categories to category (singular)
        frontmatter = re.sub(r'categories:\s*\[(.*?)\]', r'category: \1', frontmatter)
    
        # Convert published to draft
        if 'published: true' in frontmatter:
            frontmatter = frontmatter.replace('published: true', 'draft: false')
        elif 'published: false' in frontmatter:
            frontmatter = frontmatter.replace('published: false', 'draft: true')
    
        # Remove quotes from simple strings
        frontmatter = re.sub(r'"(.*?)"', r'\1', frontmatter)
    
        return f"---\n{frontmatter}\n---\n{body}"
    
    # Usage
    source_dir = Path("path/to/hugo/content")
    target_dir = Path("content")
    
    for md_file in source_dir.rglob("*.md"):
        content = md_file.read_text()
        converted = convert_frontmatter(content, source_format="hugo")
    
        # Preserve directory structure
        relative_path = md_file.relative_to(source_dir)
        target_file = target_dir / relative_path
        target_file.parent.mkdir(parents=True, exist_ok=True)
        target_file.write_text(converted)
    
        print(f"Converted: {md_file}{target_file}")
    

    Manual Migration Steps

    1. Copy content files:

      1
      2
      3
      4
      5
      6
      # From Hugo
      cp -r /path/to/hugo/content/* content/
      
      # From Jekyll
      mkdir -p content/blog
      cp -r /path/to/jekyll/_posts/* content/blog/
      
    2. Rename index files:

      1
      2
      # Hugo _index.md → Bengal _index.md (same)
      # Jekyll index.html → Bengal index.md
      
    3. Convert frontmatter:

      • Use the script above or convert manually
      • Check each file for format-specific fields
  5. 5

    Preserve URLs

    Maintain SEO and prevent broken links during migration.

    Bengal generates URLs from file paths. To preserve existing URLs:

    1. Useslugfrontmatter to override generated URLs:

      1
      2
      3
      4
      ---
      title: My Post
      slug: /old/url/path  # Preserves old URL structure
      ---
      
    2. Create redirects (if URLs must change):

      1
      2
      3
      4
      5
      # content/old-url.md
      ---
      title: Redirect
      redirect: /new-url/
      ---
      
    3. Check URL generation:

      1
      2
      bengal build
      # Check public/ directory for generated URLs
      
  6. 6

    Migrate Assets

    Move images, CSS, JS, and other static files to Bengal's asset directories.

    Bengal looks for assets in:

    • assets/- Site-specific assets
    • themes/[theme-name]/static/- Theme assets

    Migration steps:

    1. Copy static files:

      1
      2
      3
      4
      5
      # From Hugo
      cp -r /path/to/hugo/static/* assets/
      
      # From Jekyll
      cp -r /path/to/jekyll/assets/* assets/
      
    2. Update image references:

      • Hugo:![alt](images/photo.jpg)![alt](../assets/images/photo.jpg)
      • Jekyll:![alt](/assets/images/photo.jpg)![alt](../assets/images/photo.jpg)
    3. Update CSS/JS references:

      • Move toassets/css/andassets/js/
      • Update template references if using custom themes
  7. 7

    Migrate Configuration

    Convert your SSG's config file to Bengal's YAML configuration system.

    From Hugoconfig.toml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    # Hugo config.toml
    baseURL = "https://example.com"
    title = "My Site"
    languageCode = "en-us"
    
    # Converted to Bengal bengal.toml
    [site]
    baseurl = "https://example.com"
    title = "My Site"
    language = "en"
    

    From Jekyll_config.yml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    # Jekyll _config.yml
    title: My Site
    url: https://example.com
    lang: en
    
    # Converted to Bengal bengal.toml
    [site]
    title = "My Site"
    baseurl = "https://example.com"
    language = "en"
    

    Menu Configuration

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    # Bengal menu structure
    [[site.menu.main]]
    name = "Home"
    url = "/"
    weight = 1
    
    [[site.menu.main]]
    name = "Blog"
    url = "/blog/"
    weight = 2
    
  8. 8

    Test Your Migration

    Verify your content renders correctly and links work.

    Verification Steps

    • Build the site:bengal build
    • Check for errors:bengal build --verbose
    • Validate links:bengal health linkcheck
    • Preview locally:bengal serve(visit http://localhost:5173)
  9. 9

    Handle Special Cases

    Address shortcodes, taxonomies, and data files that need manual conversion.

    Taxonomies

    Bengal usestagsandcategory(singular) for taxonomies:

    1
    2
    3
    # Convert multiple categories to tags
    # Hugo: categories: [tutorial, python]
    # Bengal: category: tutorial, tags: [python]
    

    Shortcodes

    Bengal doesn't have Hugo-style shortcodes. Options:

    1. Convert to Markdown:

      1
      2
      3
      4
      5
      # Hugo shortcode
      {{< youtube id="dQw4w9WgXcQ" >}}
      
      # Bengal: Use HTML or Markdown
      <iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ"></iframe>
      
    2. Use Jinja2 templates (for advanced cases)

    Data Files

    Bengal doesn't have Jekyll-style_data/files. Options:

    1. Move toconfig/params.yaml:

      1
      2
      3
      4
      # config/params.yaml
      authors:
        - name: John Doe
          email: john@example.com
      
    2. Use Python scripts to generate content from data

Troubleshooting

Missing pages:

  • Check if files are incontent/directory
  • Verify_index.mdvsindex.mdusage
  • Check fordraft: true(excluded from builds)

Broken links:

  • Runbengal health linkcheckto find broken links
  • Update internal links to use relative paths
  • Check URL generation matches expectations

Assets not loading:

  • Verify assets are inassets/directory
  • Check image paths in content (use relative paths)
  • Ensure asset references match Bengal's structure

:::

Next Steps

3

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

flowchart TB subgraph "Your Files" A["📄 about.md"] B["📁 blog/_index.md"] C["📦 gallery/index.md"] end subgraph "Your Site" D["/about/"] E["/blog/ + children"] F["/gallery/ + assets"] end A --> D B --> E C --> F

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   (private to this page)
    └── photo-2.jpg   (private to this page)

Use for: pages with images, data files, or other assets.

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.mdcreates a section (with children).index.mdcreates a bundle (with assets). The underscore matters!

4

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 0 Sort order (lower = first)
slug string filename URL slug override
url string Complete URL path override
aliases list [] Additional URLs that redirect to this page

Taxonomy Fields

Field Type Description
tags list Tags for categorization
categories list Categories for grouping
keywords list SEO keywords
authors list Page authors (strings or objects)
author string/object Single author (string key or nested object)

Author Patterns

Bengal supports multiple author patterns for flexibility:

Simple string (reference to data registry):

author: lbliii

Nested object (inline):

1
2
3
4
author:
  name: Lawrence Lane
  github: lbliii
  bio: Technical writer and developer

Multiple authors (list of strings or objects):

1
2
3
4
authors:
  - lbliii
  - name: Jane Smith
    github: janesmith

Flat author fields (legacy pattern):

1
2
3
4
5
6
7
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:

1
2
3
4
5
6
# 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:

1
2
{% set author_info = site.data.authors[page.metadata.author] %}
{{ author_info.name }}{{ author_info.bio }}

Layout Fields

Field Type Default Description
layout string Visual variant (maps todata-varianton body). To change the template file, usetemplate.
type string section name Content type (determines default strategy and template)
template string Explicit template path (e.g.,blog/single.html)

SEO Fields

Field Type Description
canonical string Canonical URL for duplicate content
noindex boolean Iftrue, addsnoindexmeta tag
og_image string Open Graph image path
og_type string Open Graph type (article, website, etc.)
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

Any fields not part of Bengal's standard frontmatter are automatically available as custom fields. Simply add them at the top level of your frontmatter.

Standard fields (extracted to PageCore):

  • title,description,date,draft,weight,slug,url,aliases,lang
  • tags,categories,keywords,authors,category
  • type,variant,layout,template
  • canonical,noindex,og_image,og_type
  • menu,nav_title,parent
  • cascade,outputs,resources,toc

Custom fields (any other fields):

  • Any field not listed above goes intopage.props
  • Access viapage.metadata.get('field_name')orpage.props.get('field_name')

Example

1
2
3
4
5
6
7
8
9
---
title: My Page
description: Page description
weight: 10
type: doc
icon: code
card_color: blue
custom_setting: value
---

Access custom fields via:

  • page.metadata.get('icon')orpage.props.get('icon')
  • page.metadata.get('card_color')
  • page.metadata.get('custom_setting')

Note: Theprops:key is only used in skeleton manifests (bengal project skeleton apply). For regular markdown files, use flat frontmatter (all fields at top level).

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
---
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]
layout: tutorial
cascade:
  type: doc
difficulty: beginner
time_estimate: 15 minutes
---

Cascade Configuration

Thecascadefield applies values to all descendant pages:

1
2
3
4
5
6
7
---
title: Documentation
cascade:
  type: doc
  layout: docs
  draft: false
---

All pages under this section inherit these values unless they override them.

5

Configuration

Configuring Bengal with bengal.toml

Configuration

Control Bengal's behavior throughbengal.tomland environment-specific settings.

Configuration Methods

flowchart TB subgraph "Base Configuration (Mutually Exclusive)" A[bengal.toml] B[config/ directory] end C[Environment Overrides] D[CLI Flags] E[Final Config] A -.->|OR| E B -.->|OR| E C --> E D --> E

Bengal loads configuration from either theconfig/directory (preferred) ORbengal.toml(legacy/simple). Ifconfig/exists,bengal.tomlis ignored.

Overrides apply in order: Base Config → Environment Overrides → CLI Flags.

Quick Start

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# bengal.toml
[site]
title = "My Site"
base_url = "https://example.com"
language = "en"

[build]
output_dir = "public"
clean = true

[theme]
name = "default"

Configuration Patterns

Best for small sites:

1
2
3
4
5
6
7
8
9
# 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
1
2
3
4
5
6
7
# config/environments/production.yaml
site:
  base_url: "https://example.com"

build:
  minify: true
  fingerprint: true

Tip

Best practice: Keep development settings inbengal.toml, add production overrides inconfig/environments/production.yaml.

Build Options Reference

Key[build]configuration options:

Option Type Default Description
output_dir string "public" Directory for generated files
clean bool false Remove output directory before build
minify bool false Minify HTML/CSS/JS output
fingerprint bool false Add content hash to asset URLs
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

Template Validation

Enablevalidate_templatesto catch template syntax errors early during builds:

1
2
[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:

1
2
[build]
validate_templates = true

Combine with strict mode in CI pipelines to fail builds on template errors:

1
2
3
[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:

  • Jinja2 syntax errors (unclosed tags, invalid filters)
  • 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.