Bengal provides extension points for customizing content processing, adding new content sources, defining typed content schemas, and integrating external build tools.
Extension Points
Bengal supports several extension mechanisms:
| Extension Type | Use Case | Difficulty |
|---|---|---|
| Build Hooks | Run external tools (Tailwind, esbuild) before/after builds | Easy |
| Theme Customization | Override templates and CSS | Easy |
| Content Collections | Type-safe frontmatter with schema validation | Moderate |
| Template Shortcodes | Add template-only embeds without Python | Easy |
| Custom Directives | Create new MyST directive blocks | Advanced |
| Custom Content Sources | Fetch content from APIs, databases, or remote services | Advanced |
Architecture Overview
Extensions integrate at different stages of the build pipeline:
flowchart TB
subgraph "Pre-Build"
A[Build Hooks]
end
subgraph "Discovery Phase"
B[Content Sources]
C[Collections & Schemas]
end
subgraph "Processing Phase"
D[Custom Directives]
end
subgraph "Rendering Phase"
E[Theme Templates]
F[CSS Customization]
end
subgraph "Post-Build"
G[Build Hooks]
end
A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
Quick Start Examples
Build Hooks
Integrate external tools by adding hooks to yourbengal.toml:
[dev_server]
pre_build = [
"npx tailwindcss -i src/input.css -o assets/style.css"
]
post_build = [
"echo 'Build complete!'"
]
Theme Customization
Override any theme template by placing a file with the same name in your project'stemplates/directory:
your-project/
├── templates/
│ └── page.html # Overrides theme's page.html
└── bengal.toml
Content Collections
Define typed schemas for your content:
# collections.py
from dataclasses import dataclass
from datetime import datetime
from bengal.collections import define_collection
@dataclass
class BlogPost:
title: str
date: datetime
author: str = "Anonymous"
collections = {
"blog": define_collection(schema=BlogPost, directory="content/blog"),
}
Custom Directives
Create new directive blocks by subclassingBengalDirective:
from bengal.directives import BengalDirective, DirectiveToken
class AlertDirective(BengalDirective):
NAMES = ["alert"]
TOKEN_TYPE = "alert"
def parse_directive(self, title, options, content, children, state):
return DirectiveToken(
type=self.TOKEN_TYPE,
attrs={"level": title or "info"},
children=children,
)
def render(self, renderer, text, **attrs):
level = attrs.get("level", "info")
return f'<div class="alert alert-{level}">{text}</div>'
When to Extend
Choose the right extension mechanism for your needs:
- Build hooks: Integrate CSS preprocessors, JavaScript bundlers, or custom scripts
- Theme customization: Modify page layouts, add partials, or change styling
- Collections: Enforce frontmatter requirements and get IDE autocompletion
- Custom directives: Add domain-specific content blocks (alerts, embeds, widgets)
- Content sources: Pull content from GitHub, Notion, REST APIs, or databases
Related Resources
- Architecture Reference for understanding Bengal internals
- Protocol Layer for interface contracts
- Build Pipeline for pipeline phase details
- Configuration for
bengal.tomloptions
In This Section
Build Hooks
Run external tools before and after Bengal builds
Content Collections
Define typed schemas for frontmatter validation and IDE support
Create Custom Skeletons
Build reusable site structure templates with skeleton YAML
Custom Content Sources
Fetch content from APIs, databases, or remote services
Custom Directives
Create custom MyST directive blocks for specialized content
Template Shortcodes
Create template-only embeds without writing Python
Theme Customization
Override templates and customize CSS styling
Writing Plugins
Create plugins that add directives, template functions, content sources, and build hooks