# Extending Bengal URL: /bengal/docs/0.4.3/extending/ Section: extending -------------------------------------------------------------------------------- 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 your bengal.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's templates/ 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 implementing the DirectiveHandler protocol: from typing import ClassVar from patitas.nodes import Directive class AlertDirective: names: ClassVar[tuple[str, ...]] = ("alert",) token_type: ClassVar[str] = "alert" def parse(self, name, title, options, content, children, location): return Directive( location=location, name=name, title=title or "info", options=options, children=tuple(children), ) def render(self, node, rendered_children, sb): level = node.title or "info" sb.append(f'<div class="alert alert-{level}">') sb.append(rendered_children) sb.append("</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.toml options -------------------------------------------------------------------------------- Metadata: - Author: lbliii - Word Count: 398 - Reading Time: 2 minutes