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.14+, 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 the free-threaded build (Python 3.14t), which enables true parallel processing.

Install

uv pip install bengal

Or for a one-time run without installation:

uvx bengal --version
pip install bengal
pipx install bengal

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

git clone https://github.com/lbliii/bengal.git
cd bengal
make setup
make install

This installs Bengal in editable mode with development dependencies.

Verify Installation

bengal --version

You should see output like: Bengal SSG, version 0.1.10

Upgrade Bengal

Bengal includes a built-in upgrade command that automatically detects how it was installed:

# Interactive upgrade (recommended)
bengal upgrade

# Skip confirmation
bengal upgrade -y

# Preview changes without executing
bengal upgrade --dry-run

The upgrade command:

  • Detects your installer (uv, pip, pipx, conda)
  • Checks PyPI for the latest version (cached for 24 hours)
  • Shows a confirmation before making changes

Tip

Bengal will show a notification after commands when a new version is available. You can disable this by settingBENGAL_NO_UPDATE_CHECK=1in your environment.

Python Version Setup

pyenv lets you install and switch between multiple Python versions:

# 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

For best build performance, use the free-threaded Python build (Python 3.14t). This enables true parallel processing for 1.5-2x faster builds on multi-core machines.

# 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')"

Bengal automatically detects the free-threaded build and enables parallel processing.

Troubleshooting

Next Steps

2

Writer Quickstart

Create your first site and start writing content

Writer Quickstart

Create your first Bengal site and publish content in 5 minutes. No theming or code required.

Prerequisites

Before You Start

1/3 complete

Create Your Site

bengal new site myblog --template blog
cd myblog

The --template blog flag scaffolds a complete blog structure with sample posts. Other templates: default, docs, portfolio, product, resume.

Start the Dev Server

bengal serve

Your browser opens automatically at http://localhost:5173/. The server rebuilds on save—CSS changes apply instantly without page refresh.

Create Your First Post

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

This creates content/posts/my-first-post.md. Edit it:

---
title: My First Post
date: 2026-01-15
tags: [welcome]
description: Getting started with Bengal
---

# My First Post

Welcome to my blog! Bengal makes publishing simple.

## What's Next

- Add more posts with `bengal new page`
- Customize your theme
- Deploy to the web

Save. The page appears instantly in your browser.

Customize Your Site

Editconfig/_default/site.yaml:

site:
  title: "My Awesome Blog"
  description: "Thoughts on code, design, and life"
  language: "en"

Build and Deploy

bengal build

Output goes to public/. Deploy to any static host:

Platform Build Command Output
Netlify bengal build public
Vercel bengal build public
GitHub Pages bengal build public

Bengal auto-detects Netlify, Vercel, and GitHub Pages to setbaseurlautomatically. See Deployment Guide for CI/CD workflows.

Frontmatter Essentials

Every page starts with YAML frontmatter:

---
title: Page Title           # Required
date: 2026-01-15            # Publication date (ISO format)
description: SEO text       # Search/social preview
tags: [tag1, tag2]          # Taxonomy
draft: true                 # Exclude from production
---

Next Steps

3

Scaffold Your First Site

Create a Bengal site from a template in 5 minutes

Scaffold Your First Site

Bengal provides built-in templates to quickly create sites with common information architectures. This tutorial covers three ways to scaffold a site.

Quick Start: Template-Based Creation

The fastest way to start is with a template:

# Create a documentation site
bengal new site my-docs --template docs

# Navigate and preview
cd my-docs
bengal serve

Open http://localhost:5173to see your scaffolded site.

Available Templates

Template Best For Command
default Minimal single-page site bengal new site --template default
docs Technical documentation, knowledge bases bengal new site --template docs
blog Personal blogs, news sites bengal new site --template blog
portfolio Developer portfolios, project showcases bengal new site --template portfolio
product Product showcase sites bengal new site --template product
resume CV/Resume with structured data bengal new site --template resume

What Gets Created

When you runbengal new site my-docs --template docs, Bengal creates:

my-docs/
├── config/
│   ├── _default/
│   │   ├── site.yaml        # Site identity (title, author, baseurl)
│   │   ├── content.yaml     # Content processing settings
│   │   ├── build.yaml       # Build configuration
│   │   ├── features.yaml    # Feature toggles
│   │   ├── theme.yaml       # Theme configuration
│   │   └── params.yaml      # Custom variables
│   └── environments/
│       ├── local.yaml       # Development overrides
│       └── production.yaml  # Production settings
├── content/
│   ├── index.md             # Home page
│   ├── getting-started/     # Onboarding section
│   │   ├── _index.md
│   │   ├── installation.md
│   │   └── quickstart.md
│   ├── guides/              # How-to guides
│   │   └── _index.md
│   └── api/                 # API reference
│       └── _index.md
└── .gitignore

Method 1: Interactive Wizard

For a guided experience, run without arguments:

bengal new site

The wizard prompts for:

  1. Site name (creates directory)
  2. Base URL (for production deployment)
  3. Template (select from list)

Method 2: Direct Template Selection

Skip prompts with explicit options:

# Blog with custom name
bengal new site my-blog --template blog

# Portfolio at specific URL
bengal new site portfolio --template portfolio

Method 3: Add Sections to Existing Site

Already have a site? Add sections without recreating:

# Add docs and tutorials sections
bengal project init --sections docs --sections tutorials

# Add sections with sample content
bengal project init --sections blog --with-content --pages-per-section 5

Section Type Inference

Bengal infers section types from names:

Name Pattern Inferred Type Behavior
blog, posts, articles, news blog Date-sorted, post-style
docs, documentation, guides, tutorials doc Weight-sorted, doc-style
projects, portfolio section Standard section
about, contact section Standard section

Customizing After Scaffolding

  1. 1

    Update Site Identity

    Replace placeholder values with your project's actual metadata.

    Editconfig/_default/site.yaml:

    site:
      title: "My Documentation"
      description: "Documentation for my project"
      author: "Your Name"
      baseurl: "https://docs.example.com"
    
  2. 2

    Configure Features

    Enable RSS feeds, search, sitemaps, and other built-in features.

    Editconfig/_default/features.yaml:

    features:
      rss: true       # Generate RSS feed
      sitemap: true   # Generate sitemap.xml
      search: true    # Enable search
      json: true      # Generate JSON API
      llm_txt: true   # Generate llms.txt
    
  3. 3

    Add Your Content

    Replace placeholder content incontent/:

    # Edit home page
    $EDITOR content/index.md
    
    # Add new page
    touch content/getting-started/configuration.md
    

Preview and Build

# Live preview with hot reload
bengal serve

# Production build
bengal build

# Build with specific environment
bengal build --environment production

Skeleton Manifests

Bengal supports skeleton manifests — shareable YAML files that define complete site structures with frontmatter, cascades, and content stubs.

# Apply a skeleton YAML
bengal project skeleton apply api-docs.yaml

# Preview what would be created
bengal project skeleton apply api-docs.yaml --dry-run

# Overwrite existing files
bengal project skeleton apply api-docs.yaml --force

See Create Custom Skeletons for the full guide on writing skeleton YAML files.

Next Steps

Troubleshooting

4

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:

    # Create a new Bengal site
    bengal new site my-blog
    
    # Enter your site directory
    cd my-blog
    

    You will see a structure like this:

    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 in assets/.

  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.

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

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

    ---
    title: Hello World
    date: 2023-10-27T14:30:00
    ---
    
    # Hello World
    
    Your content goes here.
    

    Update it to look like this:

    ---
    title: "My First Bengal Post"
    date: 2023-10-27
    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 [[ext:kida:|Kida]] templates 🐍
    *   It's easy to configure ⚙️
    

    Tip

    Draft pages Pages are published by default. Setdraft: true in frontmatter to exclude a page from production builds. Draft pages are still visible in development mode (bengal serve).

  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.

    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 the mainmenu 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:

    /* 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.

    <!-- 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') }}">
    {% end %}
    
    {# Add a custom footer after the main content #}
    {% block footer %}
    <footer class="custom-footer">
        <p>
            &copy; {{ site.build_time | dateformat('%Y') }} {{ site.author }}.
            Built with <a href="https://lbliii.github.io/bengal">Bengal</a>.
        </p>
    </footer>
    {% end %}
    

    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 a public/directory containing your complete website: HTML, CSS, and optimized images.

    Review Build Output

    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:

5

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 HTML output (enabled by default)
  • 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 template errors. Highly Recommended for CI/CD.
--clean-output Cleans thepublic/directory before building. Recommended to avoid stale files.
--fast Maximum performance (quiet output, full parallelism). Fast CI builds.
--verbose Shows detailed build output (phase timing, stats). 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:

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 --clean-output

      - 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:

[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.txt includes bengal.

Automatic Platform Detection

Bengal auto-detects your deployment platform and configuresbaseurlautomatically:

Platform Detection Baseurl Source
GitHub Pages GITHUB_ACTIONS=true Inferred fromGITHUB_REPOSITORY
Netlify NETLIFY=true URL or DEPLOY_PRIME_URL
Vercel VERCEL=true VERCEL_URL

You can override auto-detection with theBENGAL_BASEURLenvironment variable:

BENGAL_BASEURL="https://custom-domain.com" bengal build --environment production

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 template errors.
  3. Runbengal validate: Runs health checks on your site content.
  4. Checkconfig/environments/production.yaml: Ensure your baseurlis set to your production domain.
# config/environments/production.yaml
site:
  baseurl: "https://example.com"

Seealso

6

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

Performance Tip

For faster CI builds, use Python 3.14t (free-threading build) instead of 3.14. This enables true parallel processing and can reduce build times by 1.5-2x on multi-core runners. Updatepython-version: '3.14t'in your workflows.

Steps

  1. 1

    Basic Build Workflow

    Create.github/workflows/build.yml:

    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

    Automatically deploys to GitHub Pages when you push tomain. Requires GitHub Pages enabled in repository settings.

    Create.github/workflows/deploy.yml:

    name: Deploy to Production
    
    on:
      push:
        branches: [main]
    
    # Required permissions for GitHub Pages deployment
    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'
              cache: 'pip'
    
          - 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
    

    Note: Enable GitHub Pages in your repository settings: Settings > Pages > Source: GitHub Actions.

  3. 3

    Preview Deployments

    Builds preview versions for pull requests. Comments on PRs when build succeeds. Artifacts available in workflow run.

    Create.github/workflows/preview.yml:

    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'
              cache: 'pip'
    
          - name: Install Bengal
            run: pip install bengal
    
          - name: Build site
            run: bengal build --environment preview
    
          - name: Upload preview artifacts
            uses: actions/upload-artifact@v4
            with:
              name: preview-site
              path: public/
              retention-days: 7
    
          - 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! Download artifacts from workflow run.'
                })
    
  4. 4

    Add Validation and Testing

    Add health checks to your CI pipeline:

    # .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

    Cache dependencies and build artifacts to reduce workflow time. Add these steps after Python setup:

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.14'
        cache: 'pip'  # Automatically caches pip packages
    
    - name: Cache Bengal build cache
      uses: actions/cache@v4
      with:
        path: .bengal-cache
        key: ${{ runner.os }}-bengal-${{ github.sha }}
        restore-keys: |
          ${{ runner.os }}-bengal-
    

    Note: Python setup with cache: 'pip'automatically caches pip packages. Only add Bengal cache if you use incremental builds.

  6. 6

    Environment-Specific Builds

    Use different configurations for production and preview builds. Store secrets in GitHub repository settings.

    1. Create environment configs:

    config/environments/production.yaml:

    site:
      baseurl: "https://example.com"
    
    params:
      analytics_id: "{{ env.GA_ID }}"
    

    config/environments/preview.yaml:

    site:
      baseurl: "https://preview.example.com"
    
    params:
      analytics_id: ""  # Disable analytics in preview
    

    2. Add environment variables to workflow:

    env:
      GA_ID: ${{ secrets.GA_ID }}
      API_KEY: ${{ secrets.API_KEY }}
    
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          # ... other steps ...
          - name: Build site
            run: bengal build --environment production
    

    3. Set secrets in GitHub: Settings > Secrets and variables > Actions > New repository secret

  7. 7

    Multi-Variant Builds (OSS vs Enterprise)

    Build separate doc sites from one repo. Useparams.edition and page frontmatter editionto filter content.

    jobs:
      build:
        strategy:
          matrix:
            edition: [oss, enterprise]
        steps:
          - uses: actions/checkout@v4
    
          - name: Set up Python
            uses: actions/setup-python@v5
            with:
              python-version: '3.14'
              cache: 'pip'
    
          - name: Install Bengal
            run: pip install bengal
    
          - name: Build ${{ matrix.edition }} site
            run: bengal build --environment ${{ matrix.edition }} --strict --clean-output
    
          - name: Upload artifact
            uses: actions/upload-artifact@v4
            with:
              name: site-${{ matrix.edition }}
              path: public/
    

    Ensure config/environments/oss.yaml and config/environments/enterprise.yaml set params.editionaccordingly. See Multi-Variant Builds for full setup.

Alternative Platforms

GitLab CI

Create.gitlab-ci.yml:

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:

[build]
  publish = "public"
  command = "pip install bengal && bengal build --environment production --strict"

[build.environment]
  PYTHON_VERSION = "3.14"

Vercel

Createvercel.json:

{
  "buildCommand": "pip install bengal && bengal build --environment production",
  "outputDirectory": "public",
  "installCommand": "pip install bengal"
}

Troubleshooting

Next Steps

✓ Track Complete