Your first Bengal journey—from zero experience to a live website. Install Bengal, create a blog, and deploy to GitHub Pages with automatic builds.

Tip

Duration: ~45 min | Prerequisite: Python 3.10+, GitHub account

1

Install Bengal

Install Bengal using pip, uv, or from source

Install Bengal

Requirements

Bengal requires Python 3.14 or later. For best performance, use Python 3.14t (free-threaded build).

Install

uv pip install bengal

Or for a one-time run:

uvx bengal --version
pip install bengal
pipx install bengal

This installs Bengal in an isolated environment while making thebengalcommand available globally.

1
2
3
git clone https://github.com/lbliii/bengal.git
cd bengal
pip install -e ".[dev]"

This installs Bengal in development mode.

Verify Installation

bengal --version

You should see output like:Bengal SSG, version X.X.X

Python Version Setup

pyenv lets you install and switch between multiple Python versions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# macOS (with Homebrew)
brew install pyenv

# Install Python 3.14
pyenv install 3.14.0

# Set as default
pyenv global 3.14.0

# Verify
python --version

Download Python 3.14 from python.org/downloads.

After installation, verify:python3 --version

Free-Threaded Python (Optional)

For best performance, use the free-threaded build (Python 3.14t):

1
2
3
4
5
6
# With pyenv
pyenv install 3.14.0t
pyenv global 3.14.0t

# Verify free-threading is enabled
python -c "import sys; print('Free-threaded!' if sys._is_gil_enabled() == False else 'GIL enabled')"

Why? The free-threaded build enables true parallel processing for 1.8-2x faster builds.

Troubleshooting

Next Steps

2

Writer Quickstart

Create your first site and start writing content

Writer Quickstart

Get from zero to published content in 5 minutes. This guide is for content creators who want to focus on writing.

Prerequisites

Before You Start

1/3 complete

Create Your Site

Use the interactive wizard:

1
2
bengal new site myblog
cd myblog

Choose a preset that matches your goal (Blog, Documentation, Portfolio, etc.).

Start the Dev Server

bengal serve

Open http://localhost:5173/ in your browser. The dev server automatically rebuilds when you save changes (hot reload).

Create Your First Post

bengal new page my-first-post --section blog

Editcontent/blog/my-first-post.md:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
---
title: My First Post
date: 2025-01-15
tags: [welcome, tutorial]
description: Getting started with Bengal
draft: false
---

# My First Post

Welcome to my new blog! This is my first post using Bengal.

## Why I Chose Bengal

- Fast builds with parallel processing
- Simple Markdown-based workflow
- Customizable themes and templates

Stay tuned for more!

Save the file. Your new post appears automatically!

Customize Your Site

Editconfig/_default/site.yaml:

1
2
3
4
5
site:
  title: "My Awesome Blog"
  description: "Thoughts on code, design, and life"
  baseurl: "https://myblog.com"
  language: "en"

Build for Production

bengal build

Your complete site is inpublic/, ready to deploy!

Deploy

Deploy thepublic/directory to any static hosting:

  • Netlify: Build command:bengal build, Publish:public
  • GitHub Pages: Use the workflow in Automate with GitHub Actions
  • Vercel: Build command:bengal build, Output:public

Frontmatter Reference

Common frontmatter fields:

Field Description
title Page title (required)
date Publication date
tags Tags for taxonomy (e.g.,[python, web])
weight Sort order (lower = first)
draft trueto hide from builds
description SEO description

Next Steps

Happy writing! 🎉

3

Build a Blog from Scratch

Create, configure, and customize a personal blog from scratch

Build a Blog in 15 Minutes

In this tutorial, you will build a fully functional personal blog with Bengal. We will go from an empty folder to a running website with custom content, configuration, and theming.

Note

Who is this for? This guide is for developers who want to see the full end-to-end workflow of Bengal. No prior experience with Bengal is required, but basic familiarity with the terminal is assumed.

Goal

By the end of this tutorial, you will have:

  1. Initialized a new Bengal project
  2. Created blog posts with tags and categories
  3. Configured site metadata and navigation
  4. Customized the theme (without breaking updates)
  5. Built the site for production

Prerequisites

  • Python 3.14+ installed (3.14t recommended for best performance)
  • Bengal installed (pip install bengal)

Steps

  1. 1

    Initialize Your Project

    Set up the foundation for your blog with Bengal's CLI scaffolding.

    First, let's create a new site. Open your terminal and run:

    1
    2
    3
    4
    5
    # Create a new Bengal site
    bengal new site my-blog
    
    # Enter your site directory
    cd my-blog
    

    You will see a structure like this:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    my-blog/
    ├── config/           # Configuration files
    │   ├── _default/     # Default settings
    │   └── environments/ # Environment-specific config
    ├── content/          # Your markdown files
    ├── assets/           # CSS, JS, images
    │   ├── css/
    │   ├── js/
    │   └── images/
    ├── templates/        # Theme overrides
    └── .gitignore        # Git ignore file
    

    Tip

    Why this structure? Bengal uses a directory-based configuration system that separates default settings from environment-specific overrides. Your content lives incontent/and custom styles inassets/.

  2. 2

    Create Your First Post

    Write and configure your first blog post with frontmatter metadata.

    Bengal provides a CLI to generate content with the correct frontmatter.

    1
    2
    # Create a new blog post
    bengal new page "Hello World" --section blog
    

    Opencontent/blog/hello-world.mdin your editor. You'll see the Frontmatter (metadata) at the top:

    1
    2
    3
    4
    5
    6
    7
    8
    ---
    title: Hello World
    date: 2023-10-27T14:30:00
    ---
    
    # Hello World
    
    Your content goes here.
    

    Update it to look like this:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    ---
    title: "My First Bengal Post"
    date: 2023-10-27
    draft: false
    tags: ["python", "bengal"]
    category: "tech"
    ---
    
    # Hello, World!
    
    This is my first post using **Bengal**, the Pythonic static site generator.
    
    ## Why Bengal?
    
    *   It's fast ⚡️
    *   It uses Jinja2 templates 🐍
    *   It's easy to configure ⚙️
    

    Warning

    Don't forgetdraft: false! By default, new pages are drafts. They won't show up in production builds unless you setdraft: false.

  3. 3

    Configure Your Site

    Personalize your blog with site metadata and navigation menus.

    Now, let's give your site an identity. Openconfig/_default/site.yamland update the basics.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    title: "My Awesome Blog"
    description: "Thoughts on code and coffee."
    baseurl: "https://example.com"
    author: "Jane Doe"
    language: "en"
    
    # Define navigation menu
    menu:
      main:
        - name: "Home"
          url: "/"
          weight: 1
        - name: "Blog"
          url: "/blog/"
          weight: 2
        - name: "About"
          url: "/about/"
          weight: 3
    
    • title,description: Global metadata used by themes (SEO tags, header titles).
    • menu.main: Defines the top navigation bar. Each item is an object in themainmenu list.
    • weight: Controls the sort order (lower numbers appear first).
  4. 4

    Preview Your Site

    Launch the dev server and see your blog come to life.

    Let's see what we have so far. Start the development server:

    bengal serve
    

    Open http://localhost:5173 in your browser.

    • Navigate to "Blog" to see your "Hello World" post.
    • Notice the site title and menu matches your configuration.

    Note

    Live Reload Try editinghello-world.mdwhile the server is running. Save the file, and the browser will automatically refresh with your changes!

  5. 5

    Customize the Theme

    Make your blog unique with custom styles and template overrides.

    You want your blog to stand out. Instead of forking the entire theme, we'll use Theme Inheritance to override just the parts we want to change.

    Let's change the header color and add a custom footer.

    Create a Custom CSS File

    Createassets/css/custom.css:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    /* assets/css/custom.css */
    :root {
        --primary-color: #6c5ce7; /* Purple header */
        --font-family: 'Helvetica Neue', sans-serif;
    }
    
    .custom-footer {
        text-align: center;
        padding: 2rem;
        background: #f1f2f6;
        margin-top: 4rem;
    }
    

    Override the Base Template

    Createtemplates/base.html. We will extend the default theme and inject our changes.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    <!-- templates/base.html -->
    {% extends "default::base.html" %}
    
    {# Inject our custom CSS into the head #}
    {% block extra_head %}
    <link rel="stylesheet" href="{{ asset_url('css/custom.css') }}">
    {% endblock %}
    
    {# Add a custom footer after the main content #}
    {% block footer %}
    <footer class="custom-footer">
        <p>
            &copy; {{ now.year }} {{ site.author }}.
            Built with <a href="https://bengal.dev">Bengal</a>.
        </p>
    </footer>
    {% endblock %}
    

    Check your browser. The header color should change (if the theme uses the--primary-colorvariable), and your custom footer should appear.

  6. 6

    Build for Production

    Generate optimized static files ready for deployment.

    When you're ready to publish, build the static files.

    bengal build
    

    This creates apublic/directory containing your complete website: HTML, CSS, and optimized images.

    Review Build Output

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public/
    ├── index.html
    ├── blog/
    │   ├── index.html
    │   └── hello-world/
    │       └── index.html
    └── assets/
        └── css/
            └── custom.a1b2c3d4.css  # Fingerprinted for caching
    

Next Steps

Congratulations! You've built a custom blog. Here is where to go next:

4

Deployment

Deploy your Bengal site to production

Deploy Your Site

Bengal generates static HTML, CSS, and JavaScript files. This means you can host your site anywhere that serves static files (e.g., GitHub Pages, Netlify, Vercel, AWS S3, Nginx).

The Production Build

When you are ready to ship, run the build command:

bengal build --environment production

This command:

  • Loads configuration fromconfig/environments/production.yaml(if it exists)
  • Minifies assets (if enabled)
  • Generates thepublic/directory with your complete site

Common Build Flags

Flag Description Use Case
--environment production Loads production config overrides. Always use for shipping.
--strict Fails the build on warnings (e.g., broken links). Highly Recommended for CI/CD.
--clean-output Cleans thepublic/directory before building. Recommended to avoid stale files.
--verbose Shows detailed logs. Useful for debugging CI failures.

Example full command for CI:

bengal build --environment production --strict --clean-output

GitHub Pages

Deploy using GitHub Actions. Create.github/workflows/deploy.yml:

 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
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.14'

      - name: Install Bengal
        run: pip install bengal

      - name: Build Site
        run: bengal build --environment production --strict

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: './public'

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

Netlify

Create anetlify.tomlin your repository root:

1
2
3
4
5
6
[build]
  publish = "public"
  command = "bengal build --environment production"

[build.environment]
  PYTHON_VERSION = "3.14"

Vercel

Configure your project:

  1. Build Command:bengal build --environment production
  2. Output Directory:public
  3. Ensure yourrequirements.txtincludesbengal.

Environment Variables

Bengal allows you to inject environment variables into your configuration using{{ env.VAR_NAME }}syntax in your YAML/TOML config files.

config/environments/production.yaml:

1
2
3
params:
  api_key: "{{ env.API_KEY }}"
  analytics_id: "{{ env.ANALYTICS_ID }}"

Then setAPI_KEYandANALYTICS_IDin your hosting provider's dashboard.

Pre-Deployment Checklist

Before you merge to main or deploy:

  1. Runbengal config doctor: Checks for common configuration issues.
  2. Runbengal build --strictlocally: Ensures no broken links or missing templates.
  3. Checkconfig/environments/production.yaml: Ensure yourbaseurlis set to your production domain.
1
2
3
# config/environments/production.yaml
site:
  baseurl: "https://example.com"

Seealso

5

Automate with GitHub Actions

Set up automated builds, testing, and deployments using GitHub Actions

Automate with GitHub Actions

Set up continuous integration and deployment (CI/CD) for your Bengal site. Automate builds, run tests, and deploy to production with GitHub Actions.

When to Use This Guide

  • You want automated builds on every commit
  • You need to run tests before deployment
  • You want to deploy to production automatically
  • You're setting up preview deployments for pull requests
  • You need to validate content and links before publishing

Prerequisites

  • Bengal installed
  • A Git repository on GitHub
  • A hosting provider account (GitHub Pages, Netlify, Vercel, etc.)
  • Basic knowledge of YAML

Steps

  1. 1

    Basic Build Workflow

    Create.github/workflows/build.yml:

     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
    name: Build Site
    
    on:
      push:
        branches: [main]
      pull_request:
        branches: [main]
    
    jobs:
      build:
        runs-on: ubuntu-latest
    
        steps:
          - name: Checkout code
            uses: actions/checkout@v4
    
          - name: Set up Python
            uses: actions/setup-python@v5
            with:
              python-version: '3.14'
    
          - name: Install Bengal
            run: pip install bengal
    
          - name: Build site
            run: bengal build --environment production --strict
    
          - name: Upload artifacts
            uses: actions/upload-artifact@v4
            with:
              name: site
              path: public/
              retention-days: 1
    
  2. 2

    Deploy to GitHub Pages

    Create.github/workflows/deploy.yml:

     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
    name: Deploy to Production
    
    on:
      push:
        branches: [main]
    
    permissions:
      contents: read
      pages: write
      id-token: write
    
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout code
            uses: actions/checkout@v4
    
          - name: Set up Python
            uses: actions/setup-python@v5
            with:
              python-version: '3.14'
    
          - name: Install Bengal
            run: pip install bengal
    
          - name: Build site
            run: bengal build --environment production --strict --clean-output
    
          - name: Upload artifact
            uses: actions/upload-pages-artifact@v4
            with:
              path: './public'
    
      deploy:
        environment:
          name: github-pages
          url: ${{ steps.deployment.outputs.page_url }}
        runs-on: ubuntu-latest
        needs: build
        steps:
          - name: Deploy to GitHub Pages
            id: deployment
            uses: actions/deploy-pages@v4
    
  3. 3

    Preview Deployments

    Create.github/workflows/preview.yml:

     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
    name: Preview Deployment
    
    on:
      pull_request:
        branches: [main]
    
    jobs:
      preview:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout code
            uses: actions/checkout@v4
    
          - name: Set up Python
            uses: actions/setup-python@v5
            with:
              python-version: '3.14'
    
          - name: Install Bengal
            run: pip install bengal
    
          - name: Build site
            run: bengal build --environment preview --build-drafts
    
          - name: Comment PR with preview
            uses: actions/github-script@v7
            with:
              script: |
                github.rest.issues.createComment({
                  issue_number: context.issue.number,
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  body: '✅ Preview build successful! Artifacts available in workflow run.'
                })
    
  4. 4

    Add Validation and Testing

    Add health checks to your CI pipeline:

     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
    # .github/workflows/test.yml
    name: Test and Validate
    
    on: [push, pull_request]
    
    jobs:
      validate:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
    
          - name: Set up Python
            uses: actions/setup-python@v5
            with:
              python-version: '3.14'
    
          - name: Install Bengal
            run: pip install bengal
    
          - name: Validate configuration
            run: bengal config doctor
    
          - name: Check for broken links
            run: bengal health linkcheck
    
          - name: Build with strict mode
            run: bengal build --strict --verbose
    
  5. 5

    Caching for Faster Builds

    Add caching to speed up workflows:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    - name: Cache pip packages
      uses: actions/cache@v4
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
        restore-keys: |
          ${{ runner.os }}-pip-
    
    - name: Cache Bengal build cache
      uses: actions/cache@v4
      with:
        path: .bengal-cache
        key: ${{ runner.os }}-bengal-${{ github.sha }}
        restore-keys: |
          ${{ runner.os }}-bengal-
    
  6. 6

    Environment-Specific Builds

    Create Environment Configs

    config/environments/production.yaml:

    1
    2
    3
    4
    5
    site:
      baseurl: "https://example.com"
    
    params:
      analytics_id: "{{ env.GA_ID }}"
    

    config/environments/preview.yaml:

    1
    2
    3
    4
    5
    site:
      baseurl: "https://preview.example.com"
    
    params:
      analytics_id: ""  # Disable analytics in preview
    

    Use Environment Variables

    1
    2
    3
    env:
      GA_ID: ${{ secrets.GA_ID }}
      API_KEY: ${{ secrets.API_KEY }}
    

Alternative Platforms

GitLab CI

Create.gitlab-ci.yml:

 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
image: python:3.14

stages:
  - build
  - deploy

build:
  stage: build
  script:
    - pip install bengal
    - bengal build --environment production --strict
  artifacts:
    paths:
      - public/

pages:
  stage: deploy
  script:
    - pip install bengal
    - bengal build --environment production --strict
  artifacts:
    paths:
      - public
  only:
    - main

Netlify

Createnetlify.toml:

1
2
3
4
5
6
[build]
  publish = "public"
  command = "pip install bengal && bengal build --environment production --strict"

[build.environment]
  PYTHON_VERSION = "3.14"

Vercel

Createvercel.json:

1
2
3
4
5
{
  "buildCommand": "pip install bengal && bengal build --environment production",
  "outputDirectory": "public",
  "installCommand": "pip install bengal"
}

Troubleshooting

Next Steps

← Previous: Deployment
✓ Track Complete