#static-site-generator #blog #markdown

bin+lib bim

A content-first static site generator for blogs, digital gardens, and knowledge bases

1 unstable release

0.1.0 Feb 3, 2026

#79 in #blog

MIT license

260KB
3K SLoC

bim

A content-first, convention-over-configuration static site generator written in Rust.

Designed to support blogs, digital gardens, code snippets, recipes, talks, and slides in a single coherent knowledge base.

Philosophy

  • Markdown as the primary authoring format
  • Filesystem structure as the source of truth
  • No front matter - metadata extracted from filenames and git
  • Lenient behavior - warnings instead of hard errors
  • Fast - parallel processing with Rayon

Installation

cargo install bim

Or build from source:

cargo build --release
./target/release/bim --help

Quick Start

# Create a new site
mkdir my-site && cd my-site

# Create some content
mkdir blog
echo "# Hello World" > blog/2024-01-15-hello-world.md
echo "# About" > index.md

# Build the site
bim build

# Serve locally with live reload
bim serve --watch

CLI Commands

bim build

Build the static site.

bim build                  # Build to ./dist
bim build --output public  # Build to ./public
bim build --drafts         # Include draft content
bim build --clean          # Clean output directory first

bim serve

Build and serve the site locally.

bim serve                  # Serve on http://127.0.0.1:3000
bim serve --port 8080      # Custom port
bim serve --host 0.0.0.0   # Bind to all interfaces
bim serve --watch          # Watch for changes and rebuild
bim serve --drafts         # Include draft content

bim watch

Watch for changes and rebuild.

bim watch                  # Watch and rebuild to ./dist
bim watch --drafts         # Include draft content

bim prep-images

Process images without building the full site.

bim prep-images            # Process images
bim prep-images --force    # Force reprocessing all images

Directory Structure

my-site/
├── index.md              # Homepage
├── nav.md                # Navigation menu
├── blog/                 # Blog posts (date-sorted, RSS feed)
│   ├── 2024-01-15-hello.md
│   └── 2024-02-01-update.md
├── notes/                # Hierarchical notes (auto-indexes)
│   ├── getting-started/
│   │   ├── index.md
│   │   └── installation.md
│   └── features/
│       └── backlinks.md
├── snippets/             # Code snippets (syntax highlighted)
│   ├── rust/
│   │   └── error_handling.rs
│   └── python/
│       └── decorators.py
├── talks/                # Conference talks
├── projects/             # Project pages
├── recipes/              # Recipes or tutorials
├── slides/               # Presentation slides
├── tags/                 # Custom tag pages (optional)
│   └── rust.md
├── contexts/             # Custom context pages (optional)
│   └── linux.md
├── layouts/              # Custom HTML layouts
│   └── default.html
├── static/               # Static files (copied as-is)
│   ├── css/
│   └── robots.txt
└── images/               # Images (processed/optimized)
    └── hero.jpg

Collections

Collection URL Base Features
blog /blog/ Date-sorted, RSS feed, flat structure
notes /notes/ Hierarchical, auto-indexes for directories
snippets /snippets/ Syntax highlighting, language detection
talks /talks/ Flat structure
projects /projects/ Flat structure
recipes /recipes/ Flat structure
slides /slides/ Flat structure, no backlinks
tags /tags/ Auto-generated from content
contexts /contexts/ Auto-generated from content

Content Features

Dates from Filenames

Prefix filenames with YYYY-MM-DD- to set the date:

blog/2024-01-15-my-post.md  →  /blog/my-post/

If no date prefix, the git commit date is used.

Titles from Headings

The first # Heading in your markdown becomes the page title:

# My Awesome Post

Content here...

Drafts

Files starting with _ or in _drafts/ directories are drafts:

blog/_work-in-progress.md   # Draft (underscore prefix)
blog/_drafts/ideas.md       # Draft (in _drafts directory)

Include drafts with --drafts flag.

Tags

Use [#tag name] syntax to tag content:

This post is about [#rust] and [#web development].

Tags are automatically converted to links and aggregated at /tags/.

Contexts

Use [@context name] syntax to specify contexts:

This applies to [@linux] and [@docker] environments.

Contexts are automatically converted to links and aggregated at /contexts/.

Internal links are tracked and backlinks are displayed automatically. Link to other pages:

See also [my other post](/blog/other-post/).

The linked page will show a backlink to this page.

Directives

Use directives to embed dynamic content:

## Recent Posts

{{recent blog 5}}

## Latest Notes

{{recent notes 3}}

Available directives:

  • {{recent collection count}} - List recent items from a collection

Navigation

Create nav.md to define the site navigation:

- [Home](/)
- [Blog](/blog/)
- [Notes](/notes/)
- [Snippets](/snippets/)

Layouts

Create custom layouts in the layouts/ directory. Layouts are HTML files with placeholders:

<!DOCTYPE html>
<html lang="{{lang}}" dir="{{dir}}">
<head>
    <title>{{title}}</title>
</head>
<body>
    {{nav}}
    <main>{{content}}</main>
    {{backlinks}}
    <footer>Last modified: {{last_modified}}</footer>
</body>
</html>

Available Placeholders

Placeholder Description
{{title}} Page title
{{content}} Rendered HTML content
{{nav}} Navigation HTML
{{backlinks}} Backlinks section HTML
{{last_modified}} Last modification date
{{lang}} Content language (e.g., "en", "ar")
{{dir}} Text direction ("ltr" or "rtl")

Layout Selection

Layouts are selected by collection:

  • layouts/blog.html - Blog posts
  • layouts/notes.html - Notes
  • layouts/snippets.html - Code snippets
  • layouts/slides.html - Slides
  • layouts/default.html - Fallback for all collections

Code Snippets

Place code files in snippets/ to create syntax-highlighted pages:

snippets/
├── rust/
│   └── error_handling.rs
├── python/
│   └── decorators.py
└── bash/
    └── git_aliases.sh

Each file becomes a page with:

  • Title from filename
  • Syntax highlighting
  • Backlink support

Language Detection

Content language is automatically detected:

  • English content: lang="en" dir="ltr"
  • Arabic content: lang="ar" dir="rtl"
  • Other RTL languages supported

RSS Feed

An RSS feed is automatically generated at /feed.xml for the blog collection.

Sitemap

A sitemap is automatically generated at /sitemap.xml with all pages.

Image Processing

Images in the images/ directory are:

  • Copied to output
  • Optimized for web (future: resize, compress)

Static Files

Files in static/ are copied as-is to the output:

static/css/custom.css  →  dist/css/custom.css
static/robots.txt      →  dist/robots.txt

Git Integration

If your site is in a git repository:

  • File modification dates come from git history
  • Uncommitted files use current time

Dark Mode

The default layout includes automatic dark mode support using prefers-color-scheme media query.

Example Site

See bim.gumx.cc for a complete example site demonstrating all features.

Using as a Library

bim can also be used as a library in your Rust projects:

use bim::{config::Config, discovery, render};

fn main() -> anyhow::Result<()> {
    let config = Config::default();
    let site = discovery::discover_site(&config)?;
    render::build_site(&site, &config)?;
    Ok(())
}

Environment Variables

  • RUST_LOG=bim=info - Enable info logging
  • RUST_LOG=bim=debug - Enable debug logging

License

MIT

Dependencies

~29–42MB
~674K SLoC