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