From Hugo

Onboarding guide for Hugo users migrating to Bengal

8 min read 1610 words

Good news: Bengal's content model is almost identical to Hugo's. The main difference? Shortcodes become directives.

Quick Wins (5 Minutes)

What Works The Same

Hugo Bengal Status
content/structure content/ ✅ Identical
_index.mdfor sections _index.md ✅ Identical
YAML/TOML frontmatter YAML frontmatter ✅ Identical
{{ .Params.x }} {{ page.metadata.x }} ✅ Similar
{{ .Site.Title }} {{ site.config.title }} ✅ Similar
config.toml bengal.toml ✅ Similar

The Key Difference

Hugo shortcodes → Bengal directives:

1
2
3
4
5
6
7
8
9
<!-- Hugo -->
{{</* notice warning */>}}
This is a warning
{{</* /notice */>}}

<!-- Bengal -->
:::{warning}
This is a warning
:::

Shortcode → Directive Translation

Callout Boxes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{{</* notice note */>}}
This is a note with **bold** text.
{{</* /notice */>}}

{{</* notice warning */>}}
Be careful!
{{</* /notice */>}}

{{</* notice tip */>}}
Pro tip here.
{{</* /notice */>}}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
:::{note}
This is a note with **bold** text.
:::

:::{warning}
Be careful!
:::

:::{tip}
Pro tip here.
:::

Tabs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{{</* tabs */>}}
{{</* tab "Python" */>}}
```python
print("Hello")
```
{{</* /tab */>}}
{{</* tab "JavaScript" */>}}
```javascript
console.log("Hello");
```
{{</* /tab */>}}
{{</* /tabs */>}}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
:::{tab-set}
:::{tab} Python
```python
print("Hello")
```
:::{/tab}
:::{tab} JavaScript
```javascript
console.log("Hello");
```
:::{/tab}
:::{/tab-set}

Code Highlighting

1
2
3
4
5
{{</* highlight python "linenos=table,hl_lines=2" */>}}
def hello():
    print("Hello!")  # highlighted
    return True
{{</* /highlight */>}}
1
2
3
4
5
```python
def hello():
    print("Hello!")  # use comments to draw attention
    return True
```

Figure / Image

{{</* figure src="/static/images/photo.jpg" title="My Photo" caption="A description" */>}}
1
2
3
4
5
:::{figure} /images/photo.jpg
:alt: My Photo
:caption: A description
:align: center
:::

Tip

Bengal's{figure}directive produces semantic HTML (<figure>+<figcaption>) with proper accessibility support. The:alt:option is required for images. Use:alt:with an empty value for decorative images.

YouTube Embed

{{</* youtube dQw4w9WgXcQ */>}}
1
2
3
:::{youtube} dQw4w9WgXcQ
:title: Video Title (required for accessibility)
:::

Tip

Bengal's{youtube}directive uses privacy-enhanced mode by default (youtube-nocookie.com), which is better for GDPR compliance.

All Media Embed Directives

Bengal provides built-in directives for all common media embeds:

Hugo Shortcode Bengal Directive Notes
{{</* youtube id */>}} :::{youtube} id Privacy-enhanced by default
{{</* youtube id autoplay="true" */>}} :::{youtube} id
:autoplay: true
Options as directive options
{{</* vimeo id */>}} :::{vimeo} id
:title: Title
DNT mode by default
{{</* gist user id */>}} :::{gist} user/id Combined user/id format
{{</* gist user id "file.py" */>}} :::{gist} user/id
:file: file.py
File as option
{{</* figure src="..." */>}} :::{figure} path
:alt: Alt text
Semantic HTML output
{{</* figure src="..." caption="..." */>}} :::{figure} path
:caption: ...
Caption as option
N/A :::{video} /path.mp4 Self-hosted video
N/A :::{audio} /path.mp3 Self-hosted audio
N/A :::{codepen} user/pen CodePen embeds
N/A :::{codesandbox} id CodeSandbox embeds
N/A :::{stackblitz} id StackBlitz embeds
N/A :::{asciinema} id Terminal recordings

All directives with iframes require:title:for accessibility.


Template Variable Mapping

Page Variables

Hugo Bengal Notes
{{ .Title }} {{ page.title }} Page title
{{ .Content }} {{ content }} Rendered content
{{ .Date }} {{ page.date }} Publication date
{{ .Params.x }} {{ page.metadata.x }} Custom frontmatter
{{ .Summary }} {{ page.excerpt }} Auto-generated
{{ .WordCount }} {{ page.word_count }} Word count
{{ .ReadingTime }} {{ page.reading_time }} Minutes to read
{{ .Permalink }} {{ page.url }} Full URL
{{ .RelPermalink }} {{ page.path }} Relative path

Site Variables

Hugo Bengal Notes
{{ .Site.Title }} {{ site.config.title }} Site title
{{ .Site.BaseURL }} {{ site.config.baseurl }} Base URL
{{ .Site.Params.x }} {{ site.config.params.x }} Custom params
{{ .Site.Pages }} {{ site.pages }} All pages
{{ .Site.Menus }} {{ site.menus }} Menu data

Variable Substitution in Content

Bengal supports variable substitution directly in markdown (not just templates):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
---
title: Release Notes
version: "2.5.0"
release_date: "2025-01-15"
---

# {{ page.title }}

**Version {{ page.metadata.version }}** released on {{ page.metadata.release_date }}.

Current site: {{ site.config.title }}

Tip

This is unique to Bengal—Hugo only supports variables in templates, not content files.


Configuration Mapping

Basic Site Config

1
2
3
4
5
6
7
8
baseURL = "https://example.com"
title = "My Site"
languageCode = "en-us"
theme = "docsy"

[params]
  description = "My awesome site"
  github_repo = "https://github.com/user/repo"
1
2
3
4
5
6
7
8
9
[site]
baseurl = "https://example.com"
title = "My Site"
language = "en"
theme = "bengal"

[site.params]
description = "My awesome site"
github_repo = "https://github.com/user/repo"
1
2
3
4
5
6
7
8
9
[[menu.main]]
  name = "Docs"
  url = "/docs/"
  weight = 10

[[menu.main]]
  name = "Blog"
  url = "/blog/"
  weight = 20
1
2
3
4
5
6
7
8
9
[[site.menu.main]]
name = "Docs"
url = "/docs/"
weight = 10

[[site.menu.main]]
name = "Blog"
url = "/blog/"
weight = 20

Directory Structure Comparison

Hugo Bengal Notes
content/ content/ ✅ Same
static/ assets/ Different name
layouts/ templates/ Template location
themes/ themes/ ✅ Same
data/ data/ ✅ Same
config.toml bengal.toml Different name
archetypes/ Not used Use templates
resources/ Auto-managed No equivalent

What Bengal Adds (Hugo Doesn't Have Built-in)

Cards Grid

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
:::{cards}
:columns: 3

:::{card} Feature 1
:icon: 🚀
:link: /docs/feature1/

Quick description
:::

:::{card} Feature 2
:icon: 📦
:link: /docs/feature2/

Another feature
:::

:::{/cards}

Visual Steps

1
2
3
4
5
:::{steps}

:::{step} Install
```bash
pip install bengal

:::{/step}

  • 1

    Create Site

    bengal new site mysite
    
  • 1

    Start Server

    bengal serve
    
  • :::{/steps}

    
    ### Interactive Data Tables
    
    ```markdown
    :::{data-table}
    :source: data/products.yaml
    :columns: name, price, stock
    :sortable: true
    :filterable: true
    :::
    

    Centralized Glossary

    1
    2
    3
    4
    5
    <!-- Define in data/glossary.yaml -->
    <!-- Use in any page: -->
    :::{glossary}
    :tags: api, authentication
    :::
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <!-- Auto-generate from section children -->
    :::{child-cards}
    :columns: 2
    :::
    
    <!-- Show sibling pages -->
    :::{siblings}
    :::
    
    <!-- Prev/Next navigation -->
    :::{prev-next}
    :::
    

    What's Different (Honest Gaps)

    Hugo Feature Bengal Status Workaround
    Custom shortcodes Use directives Built-in directives cover most cases
    Go templates Jinja2 templates Similar concepts, different syntax
    Hugo Modules Local themes only Copy theme files
    .GetPagefunction Template functions Different API
    Image processing Not built-in External tools
    Multilingual i18n langfrontmatter Simpler approach

    Template Syntax Differences

    Hugo (Go) Bengal (Jinja2)
    {{ if .Params.x }} {% if page.metadata.x %}
    {{ range .Pages }} {% for page in pages %}
    {{ .Title \| upper }} {{ page.title \| upper }}
    {{ with .Params.x }} {% if page.metadata.x %}
    {{ partial "name" . }} {% include "partials/name.html" %}

    Migration Steps

    1. 1

      Copy Content

      1
      2
      3
      4
      # Copy your Hugo content
      cp -r /path/to/hugo/content/* content/
      
      # Content structure is compatible
      
    2. 2

      Convert Frontmatter

      The only change:categories(plural) →category(singular)

      1
      2
      3
      4
      5
      6
      # Hugo
      categories: [tutorial, python]
      
      # Bengal
      category: tutorial
      tags: [python]  # Use tags for multiple
      
    3. 3

      Convert Shortcodes

      Search for{{<and replace with directives:

      1
      2
      # Find all shortcode usages
      grep -r "{{<" content/
      

      Common conversions:

      Find Replace With
      {{</* notice note */>}}...{{</* /notice */>}} :::{note}...:::
      {{</* highlight python */>}}...{{</* /highlight */>}} ```python...```
      {{</* tabs */>}}...{{</* /tabs */>}} :::{tab-set}...:::{/tab-set}
    4. 4

      Update Config

      1
      2
      3
      4
      # Rename config
      mv config.toml bengal.toml
      
      # Update format (see config mapping above)
      
    5. 5

      Test

      1
      2
      3
      bengal build
      bengal health linkcheck
      bengal serve
      

    Migration Checklist

    Before You Start

    • Install Bengal:pip install bengal
    • Backup your Hugo site
    • Create new Bengal site:bengal new site mysite

    Content Migration

    • Copycontent/directory
    • Convert shortcodes to directives
    • Updatecategoriescategoryin frontmatter
    • Check variable syntax in templates

    Assets Migration

    • Copystatic/toassets/
    • Update asset paths in content if needed

    Config Migration

    • Convertconfig.tomltobengal.toml
    • Update menu configuration
    • Set theme and other options

    Verify

    • Build:bengal build
    • Check:bengal health linkcheck
    • Preview:bengal serve

    Quick Reference Card

    Task Hugo Bengal
    New site hugo new site bengal new site
    Build hugo bengal build
    Serve hugo server bengal serve
    New content hugo new docs/page.md Create file directly
    Check links External tool bengal health linkcheck
    Note callout {{</* notice note */>}} :::{note}
    Warning {{</* notice warning */>}} :::{warning}
    Tabs {{</* tabs */>}} :::{tab-set}
    Code {{</* highlight */>}} ```lang

    Next Steps