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:
<!-- Hugo -->
{{</* notice warning */>}}
This is a warning
{{</* /notice */>}}
<!-- Bengal -->
:::{warning}
This is a warning
:::
Shortcode → Directive Translation
Callout Boxes
{{</* notice note */>}}
This is a note with **bold** text.
{{</* /notice */>}}
{{</* notice warning */>}}
Be careful!
{{</* /notice */>}}
{{</* notice tip */>}}
Pro tip here.
{{</* /notice */>}}
:::{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
{{</* highlight python "linenos=table,hl_lines=2" */>}}
def hello():
print("Hello!") # highlighted
return True
{{</* /highlight */>}}
```python
def hello ():
print ( "Hello!" ) # use comments to draw attention
return True
```
{{</* figure src="/static/images/photo.jpg" title="My Photo" caption="A description" */>}}
:::{figure} /images/photo.jpg
:alt: My Photo
:caption: A description
:align: center
:::
Tip
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 */>}}
:::{youtube} dQw4w9WgXcQ
:title: Video Title (required for accessibility)
:::
Tip
Tip
Bengal's{youtube}directive uses privacy-enhanced mode by default (youtube-nocookie.com), which is better for GDPR compliance.
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):
---
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
Tip
This is unique to Bengal—Hugo only supports variables in templates, not content files.
Configuration Mapping
Basic Site Config
baseURL = "https://example.com"
title = "My Site"
languageCode = "en-us"
theme = "docsy"
[params]
description = "My awesome site"
github_repo = "https://github.com/user/repo"
[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"
[[menu.main]]
name = "Docs"
url = "/docs/"
weight = 10
[[menu.main]]
name = "Blog"
url = "/blog/"
weight = 20
[[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
:::{steps}
:::{step} Install
```bash
pip install bengal
:::{/step}
1 Create Site
1 Start Server
:::{/steps}
### Interactive Data Tables
```markdown
:::{data-table}
:source: data/products.yaml
:columns: name, price, stock
:sortable: true
:filterable: true
:::
Centralized Glossary
<!-- Define in data/glossary.yaml -->
<!-- Use in any page: -->
:::{glossary}
:tags: api, authentication
:::
Navigation Directives
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 Copy Content # Copy your Hugo content
cp -r /path/to/hugo/content/* content/
# Content structure is compatible
2 Convert Frontmatter The only change:categories(plural) →category(singular)
# Hugo
categories : [ tutorial , python ]
# Bengal
category : tutorial
tags : [ python ] # Use tags for multiple
3 Convert Shortcodes Search for{{<and replace with directives:
# 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 Update Config # Rename config
mv config.toml bengal.toml
# Update format (see config mapping above)
5 Test bengal build
bengal health linkcheck
bengal serve
Migration Checklist
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