Migrate from Hugo

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

7 min read 1362 words

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