A fast static site generator written in Rust.
Live Demo Β· cargo install bamboo-cli
Bamboo transforms markdown content with frontmatter into static HTML sites. It features syntax highlighting, Tera templating, live reload development, shortcodes, asset optimization, responsive images, and generates RSS/Atom feeds, sitemaps, and search indexes automatically.
| Feature | Description |
|---|---|
| Markdown | Full CommonMark support with tables, footnotes, strikethrough, task lists |
| Frontmatter | TOML (+++) or YAML (---) metadata in content files |
| Syntax Highlighting | Built-in highlighting via syntect with configurable themes |
| Templating | Tera templates with inheritance, includes, filters, and macros |
| Shortcodes | Inline ({{</* name */>}}) and block ({{%/* name */%}}) shortcodes with Tera templates |
| Collections | Organize content beyond posts β projects, recipes, portfolios (supports nesting) |
| Data Files | Load TOML/YAML/JSON from data/ directory into templates |
| Pagination | Automatic pagination for post listings, tag pages, and category pages |
| Tags & Categories | Auto-generated tag and category index/listing pages |
| Table of Contents | Auto-generated heading-based TOC available in templates |
| Reading Time | Word count and estimated reading time for all content |
| Search | Client-side search with auto-generated JSON index and Fuse.js |
| Feeds | Automatic RSS and Atom feed generation |
| Sitemap | Automatic sitemap.xml generation |
| Redirects | redirect_from frontmatter for old URL redirects |
| Asset Pipeline | CSS/JS/HTML minification and content-hash fingerprinting |
| Responsive Images | Automatic resizing and <picture> srcset generation |
| Live Reload | Development server with automatic rebuild on file changes |
| Sass/SCSS | Automatic Sass/SCSS compilation to CSS |
| Math | LaTeX math rendering with KaTeX support ($...$ inline, $$...$$ display) |
| Custom Taxonomies | Define custom taxonomies beyond tags and categories |
| Custom Permalinks | Override output URL via permalink frontmatter field |
| Cross-References | Link between content with {{</* ref "page.md" */>}} shortcodes |
| Incremental Builds | Only rebuild changed content during development |
| Themes | Built-in default theme with light/dark mode, or use custom themes with overrides |
cargo install bamboo-cli
bamboo new my-site
cd my-site
bamboo serveOpen http://localhost:3000 to see your site. Edit files and watch them rebuild instantly.
Use the bamboo-template for a ready-to-deploy starter with GitHub Pages CI included.
bamboo new <name> # Create a new site in a new directory
bamboo init # Initialize a site in the current directory
bamboo build # Build the site to dist/
bamboo build --drafts # Include draft content
bamboo build --theme ./mytheme # Use a custom theme
bamboo build --output ./public # Custom output directory
bamboo build --base-url <url> # Override base URL
bamboo serve # Dev server with live reload at localhost:3000
bamboo serve --port 8080 # Custom port
bamboo serve --open # Open browser automatically
bamboo serve --drafts # Include drafts in dev servermy-site/
βββ bamboo.toml # Site configuration
βββ content/
β βββ _index.md # Home page
β βββ about.md # Static page β /about/
β βββ docs/ # Nested pages
β β βββ _index.md # β /docs/
β βββ posts/ # Blog posts β /posts/<slug>/
β β βββ 2024-01-15-hello.md
β βββ projects/ # Collection (needs _collection.toml)
β βββ _collection.toml
β βββ my-project.md
β βββ archived/ # Nested subdirectories supported
β βββ old-project.md
βββ data/ # Data files accessible in templates
β βββ nav.toml # β {{ site.data.nav }}
βββ static/ # Copied as-is to output
β βββ images/
βββ templates/ # Site-level template overrides
βββ shortcodes/ # Custom shortcode templates
bamboo.toml:
title = "My Site"
base_url = "https://example.com"
description = "A site built with Bamboo"
author = "Your Name"
language = "en"
posts_per_page = 10 # Posts per page (0 = all on one page)
syntax_theme = "base16-ocean.dark" # Syntax highlighting theme
math = false # Enable LaTeX math rendering
minify = false # Minify CSS, JS, and HTML output
fingerprint = false # Content-hash asset filenames for cache busting
[taxonomies.tags] # Built-in (auto-configured)
singular = "tag"
[taxonomies.categories] # Built-in (auto-configured)
singular = "category"
[images] # Responsive image generation (optional)
widths = [320, 640, 1024, 1920]
quality = 80
formats = ["webp", "jpg"]
[extra]
github = "https://github.com/username"All [extra] fields are available in templates as {{ site.config.extra.github }}.
TOML style:
+++
title = "My Post"
date = "2024-01-15"
tags = ["rust", "web"]
categories = ["tutorials"]
draft = false
weight = 10
template = "custom.html"
excerpt = "Custom excerpt text"
redirect_from = ["/old-url/"]
+++
Your content here...YAML style:
---
title: My Post
date: 2024-01-15
tags:
- rust
- web
---
Your content here...| Field | Type | Applies to | Description |
|---|---|---|---|
title |
string | all | Page/post title (defaults to filename) |
date |
date | posts | Publication date (or parsed from filename) |
draft |
bool | all | Exclude from build unless --drafts flag |
tags |
array | posts | Post tags for tag pages |
categories |
array | posts | Post categories for category pages |
weight |
number | pages, items | Sort order (lower = first) |
template |
string | all | Override default template |
excerpt |
string | posts | Custom excerpt (auto-generated from first paragraph if omitted) |
permalink |
string | all | Override the output URL (e.g. /custom-path/) |
redirect_from |
array | posts, pages | Old URLs that redirect to this content |
math |
bool | all | Enable LaTeX math for this page (when not globally enabled) |
Posts can embed dates in filenames: 2024-01-15-hello-world.md extracts date 2024-01-15 and slug hello-world.
Pages can be organized in subdirectories. Use _index.md for directory index pages:
content/docs/_index.mdβ/docs/content/docs/getting-started.mdβ/docs/getting-started/
Shortcodes embed reusable components in markdown content.
{{</* youtube id="dQw4w9WgXcQ" */>}}
{{</* figure src="/images/photo.jpg" caption="A photo" */>}}
{{</* gist user="username" id="abc123" */>}}Block shortcodes wrap markdown content:
{{%/* note type="warning" title="Heads up" */%}}
This content is rendered as **markdown** inside the shortcode.
{{%/* /note */%}}
{{%/* details summary="Click to expand" */%}}
Hidden content here.
{{%/* /details */%}}| Shortcode | Type | Parameters |
|---|---|---|
youtube |
inline | id (required), title |
figure |
inline | src (required), alt, caption, width, height, class |
gist |
inline | user (required), id (required), file |
note |
block | type (info/warning/error), title, body content |
details |
block | summary, open, body content |
Place Tera HTML templates in templates/shortcodes/. Parameters become template variables:
<!-- templates/shortcodes/alert.html -->
<div class="alert alert-{{ level }}">{{ body }}</div>{{%/* alert level="danger" */%}}
Something went wrong!
{{%/* /alert */%}}Bamboo uses Tera for templating. Templates live in your theme's templates/ directory. Site-level templates in templates/ override theme templates.
All templates receive:
| Variable | Description |
|---|---|
site.config |
bamboo.toml contents |
site.config.title |
Site title |
site.config.base_url |
Base URL |
site.config.extra.* |
Custom fields from [extra] |
site.pages |
All pages (for navigation) |
site.data |
Data from data/ directory |
site.collections |
Map of collection name to collection |
Index template (index.html):
| Variable | Description |
|---|---|
posts |
Posts for current page (first posts_per_page) |
home / page |
Home page content (from _index.md) |
current_page |
Current page number |
total_pages |
Total number of pages |
next_page_url |
URL to next page (if exists) |
Post template (post.html):
| Variable | Description |
|---|---|
post.title |
Post title |
post.content |
Rendered HTML (use {{ post.content | safe }}) |
post.date |
Publication date |
post.tags |
Tag list |
post.categories |
Category list |
post.excerpt |
Auto-generated or custom excerpt |
post.slug |
URL slug |
post.url |
Full URL path |
post.word_count |
Word count |
post.reading_time |
Estimated minutes to read |
post.toc |
Table of contents entries |
prev_post |
Previous (older) post |
next_post |
Next (newer) post |
Page template (page.html):
| Variable | Description |
|---|---|
page.title |
Page title |
page.content |
Rendered HTML |
page.slug |
URL slug |
page.url |
Full URL path |
page.word_count |
Word count |
page.reading_time |
Estimated minutes to read |
page.toc |
Table of contents entries |
Tag/Category page templates (tag.html, category.html):
| Variable | Description |
|---|---|
tag_name / category_name |
Display name |
tag_slug / category_slug |
URL slug |
posts |
Posts with this tag/category (paginated) |
current_page, total_pages |
Pagination info |
prev_page_url, next_page_url |
Pagination links |
Collection templates (collection.html, collection_item.html):
| Variable | Description |
|---|---|
collection |
Collection with name and items |
collection_name |
Collection name |
item |
Current item (in item template) |
| Filter | Description |
|---|---|
slugify |
Convert text to URL slug |
reading_time |
Estimated minutes to read content |
word_count |
Count words in content |
toc |
Render table of contents as HTML (use with | safe) |
{% extends "base.html" %}
{% block content %}
<article>
<h1>{{ post.title }}</h1>
<time>{{ post.date | date(format="%B %d, %Y") }}</time>
<span>{{ post.reading_time }} min read</span>
<div class="tags">
{% for tag in post.tags %}
<a href="{{ site.config.base_url }}/tags/{{ tag | slugify }}/">{{ tag }}</a>
{% endfor %}
</div>
{{ post.content | safe }}
</article>
{% endblock %}Place TOML, YAML, or JSON files in data/. They're accessible as site.data.<filename>.
# data/social.toml
[[links]]
name = "GitHub"
url = "https://github.com/username"
[[links]]
name = "Twitter"
url = "https://twitter.com/username"<!-- In template -->
{% for link in site.data.social.links %}
<a href="{{ link.url }}">{{ link.name }}</a>
{% endfor %}Nested directories work: data/nav/main.toml β site.data.nav.main
Bamboo includes a built-in default theme with light/dark mode toggle. Create custom themes by specifying a theme directory:
bamboo build --theme ./my-thememy-theme/
βββ templates/
β βββ base.html
β βββ index.html
β βββ page.html
β βββ post.html
β βββ collection.html
β βββ collection_item.html
β βββ tags.html
β βββ tag.html
β βββ categories.html
β βββ category.html
β βββ pagination.html
β βββ search.html
β βββ 404.html
β βββ shortcodes/
β β βββ *.html
β βββ partials/
β βββ header.html
β βββ footer.html
β βββ nav.html
βββ static/
βββ css/
Override specific templates without creating a full theme by placing templates in your site's templates/ directory. These take priority over theme templates.
The repository includes example sites:
| Example | Description | Command |
|---|---|---|
blog |
Standard blog with posts, pages, collections | just example blog |
book |
Book with chapters, sidebar navigation, prev/next | just example book |
changelog |
Software release notes and changelog | just example changelog |
docs |
Documentation site with sidebar navigation | just example docs |
landing |
Product landing page with pricing | just example landing |
portfolio |
Creative portfolio with project showcase | just example portfolio |
slideshow |
Presentation/slideshow site | just example slideshow |
Building generates:
dist/
βββ index.html # Home page
βββ style.css # Theme stylesheet (built-in theme)
βββ 404.html # Not found page
βββ about/index.html # Static pages
βββ posts/
β βββ hello/index.html # Blog posts
βββ tags/
β βββ index.html # Tags listing
β βββ rust/index.html # Per-tag post listing
βββ categories/
β βββ index.html # Categories listing
β βββ tutorials/index.html # Per-category post listing
βββ page/
β βββ 2/index.html # Pagination pages
βββ search/
β βββ index.html # Search page
βββ projects/
β βββ index.html # Collection index
β βββ my-project/index.html # Collection items
β βββ archived/
β βββ old-project/index.html # Nested collection items
βββ rss.xml # RSS feed
βββ atom.xml # Atom feed
βββ sitemap.xml # Sitemap
βββ search-index.json # Client-side search index
Use bamboo-ssg as a library in your own tools:
[dependencies]
bamboo-ssg = "0.2.5"use bamboo_ssg::{SiteBuilder, ThemeEngine};
let mut builder = SiteBuilder::new("./my-site")
.base_url("https://example.com")
.include_drafts(false);
let site = builder.build()?;
let theme = ThemeEngine::new("default")?;
theme.render_site(&site, "./dist")?;Dual-licensed under MIT (LICENSE-MIT) or Apache 2.0 (LICENSE-APACHE).