24 releases (4 breaking)

Uses new Rust 2024

new 0.5.3 Apr 19, 2026
0.5.2 Apr 19, 2026
0.4.2 Apr 19, 2026
0.3.7 Apr 18, 2026
0.1.2 Feb 9, 2026

#445 in Command line utilities

MIT/Apache

390KB
8K SLoC

bamboo ๐ŸŽ‹

github crates.io docs.rs license

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.

Features

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

Quick Start

cargo install bamboo-cli
bamboo new my-site
cd my-site
bamboo serve

Open http://localhost:3000 to see your site. Edit files and watch them rebuild instantly.

Template

Use the bamboo-template for a ready-to-deploy starter with GitHub Pages CI included.

CLI Commands

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 server

Project Structure

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

Configuration

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
link_check_ignore = []  # Paths the link validator treats as external (e.g. ["/other-project"])

[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 }}.

Content

Frontmatter

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

Frontmatter Fields

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)

Date from Filename

Posts can embed dates in filenames: 2024-01-15-hello-world.md extracts date 2024-01-15 and slug hello-world.

Nested Pages

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

Shortcodes embed reusable components in markdown content.

Inline Shortcodes

{{</* youtube id="dQw4w9WgXcQ" */>}}
{{</* figure src="/images/photo.jpg" caption="A photo" */>}}
{{</* gist user="username" id="abc123" */>}}
{{</* pdf src="/resume.pdf" title="Resume" */>}}
{{</* pdf src="/resume.pdf" embed="true" height="800" */>}}

Block Shortcodes

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 */%}}

Built-in Shortcodes

Shortcode Type Parameters
youtube inline id (required), title
figure inline src (required), alt, caption, width, height, class
gist inline user (required), id (required), file
pdf inline src (required), title, embed ("true"/"false", default "false"), height (px, default 600), download ("true"/"false", default "true")
note block type (info/warning/error), title, body content
details block summary, open, body content

Custom Shortcodes

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 */%}}

Shortcode templates also receive a base_url variable matching site.config.base_url. Use it to resolve author-provided local paths so content works correctly when deployed under a subpath:

<!-- templates/shortcodes/download.html -->
{% if src is starting_with("http") %}
  {% set resolved = src %}
{% else %}
  {% set resolved = base_url ~ src %}
{% endif %}
<a href="{{ resolved | safe }}" download>{{ label | default(value="Download") }}</a>

Templating

Bamboo uses Tera for templating. Templates live in your theme's templates/ directory. Site-level templates in templates/ override theme templates.

Template Context

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)

Custom Filters

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)

Template Example

{% 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 %}

Data Files

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

Themes

Bamboo includes a built-in default theme with light/dark mode toggle. Create custom themes by specifying a theme directory:

bamboo build --theme ./my-theme

Theme Structure

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

Theme Overrides

Override specific templates without creating a full theme by placing templates in your site's templates/ directory. These take priority over theme templates.

Examples

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

Portfolio Template

Set template = "portfolio.html" in content/_index.md to use the built-in portfolio layout. Every section is optional, and each one only renders if its data source is present.

Config fields (all under [extra] in bamboo.toml):

Field Description
avatar URL or local path to your photo
tagline Short subtitle under the hero name
linkedin LinkedIn profile URL โ†’ shows a LinkedIn button in the hero
github GitHub profile URL โ†’ shows a GitHub button in the hero
hero_pdf Path to a PDF โ†’ shows a hero button that opens a modal viewer with a download link
hero_pdf_label Text for the hero PDF button (defaults to "View PDF"; e.g. set to "Resume" for a resume)
book_url URL โ†’ shows a "Book" button in the hero
articles_url URL โ†’ shows an "Articles" link in the nav
sponsor_url URL โ†’ shows a "Sponsor" button in the nav
source_url URL โ†’ shows a GitHub source icon in the nav

Local paths (anything not starting with http, https, or //) are automatically prefixed with site.config.base_url.

Data files (under data/):

File Shape Drives
highlights.toml [[items]] with title, description, image, link, optional demo_link + demo_label Highlights grid
experience.toml [[jobs]] with title, company, period, achievements = [...] Experience section with Show-All/Timeline toggle
crates.toml Optional title plus [[items]] with title, description, link, technologies = [...] Published Crates section with A-Z/Z-A sort
projects.toml Optional title plus [[items]] with title, description, link, technologies = [...] Projects section with A-Z/Z-A sort
education.toml [[degrees]] with degree, institution, period, description Education section

Blog Layout (Author Profile Sidebar)

The default index.html, post.html, and page.html templates render with a sticky two-column author profile sidebar when [extra.author_profile] is set. When the field is absent the layout falls back to single-column (no breakage for existing sites).

[extra.author_profile]
name = "Jane Doe"
avatar = "/bio-photo.jpg"   # local path or full URL
bio = "Writing about distributed systems and compression."

[[extra.author_profile.links]]
label = "Email"
url = "mailto:jane@example.com"
icon = "envelope"

[[extra.author_profile.links]]
label = "GitHub"
url = "https://github.com/jane"
icon = "github"

[[extra.author_profile.links]]
label = "RSS"
url = "/rss.xml"
icon = "rss"

Supported icon values: envelope / email / mail, github, linkedin, twitter / x, mastodon, rss, website / globe / link. Unknown or omitted icon falls back to a generic link glyph.

Post Features

post.html composes a set of slot partials. Each slot is opt-out via [extra] toggles (default true):

Partial [extra] toggle Renders
partials/post_breadcrumbs.html post_breadcrumbs Home / Category / Post above the title (requires categories frontmatter)
partials/post_header.html always Title, date, author, read time, tags
partials/post_hero_image.html extra.image in post frontmatter Banner image above the title (also used as og:image)
partials/post_toc.html post_toc Collapsible table of contents, when the post has >= 2 headings
partials/post_share.html post_share Share on X, LinkedIn, copy-link buttons
partials/post_related.html post_related Top 3 posts by shared tags/categories, computed at build time
partials/post_prev_next.html always Previous / next navigation
partials/post_edit_link.html extra.edit_url_base "Edit this post on GitHub" link

Feature image is set per-post via frontmatter:

+++
title = "My Post"
tags = ["rust"]

[extra]
image = "/images/header.jpg"
image_alt = "A descriptive alt text"
image_caption = "Optional caption"
+++

Local paths are prefixed with site.config.base_url automatically. The image also becomes the og:image meta tag for social share cards.

Edit-on-GitHub link is enabled globally by setting extra.edit_url_base to your repo's edit URL. The link resolves to {edit_url_base}/content/posts/{slug}.md unless overridden by extra.source_path in the post frontmatter.

Social Meta Tags

Open Graph and Twitter Card meta tags are emitted on every page automatically. The og:image / twitter:image chooses, in order:

  1. Per-post extra.image
  2. Per-page extra.image
  3. Site-wide extra.og_image
  4. Author profile avatar (extra.author_profile.avatar)

Optional: set extra.twitter_handle = "@yoursite" to attribute the card.

Posts-by-Year Archive

Create content/archive.md (or any path) with the archive template:

+++
title = "Archive"
template = "archive.html"
+++

Every post, grouped by year.

The template iterates site.posts and groups entries by year. The author-profile sidebar renders alongside if configured.

Grouped Category / Tag Archives

For a Jekyll-style "all posts grouped by tag on one page" layout, use the grouped templates:

+++
title = "Posts by Category"
template = "categories_grouped.html"
+++

Every post, grouped by category.

tags_grouped.html is the tag equivalent. They complement (not replace) the per-tag and per-category index pages generated automatically under /tags/<name>/ and /categories/<name>/.

Output

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

As a Library

Use bamboo-ssg as a library in your own tools:

[dependencies]
bamboo-ssg = "0.5.3"
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")?;

License

Dual-licensed under MIT (LICENSE-MIT) or Apache 2.0 (LICENSE-APACHE).

Dependencies

~47โ€“65MB
~891K SLoC