1 unstable release
| 0.1.0 | Feb 3, 2026 |
|---|
#79 in #blog
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/.
Backlinks
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 postslayouts/notes.html- Noteslayouts/snippets.html- Code snippetslayouts/slides.html- Slideslayouts/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 loggingRUST_LOG=bim=debug- Enable debug logging
Links
- Repository: https://git.sr.ht/~gumx/bim
- Website: https://bim.gumx.cc
License
MIT
Dependencies
~29–42MB
~674K SLoC