Learn by building
Your first site
Build the smallest complete site shape with typed content, explicit routes, and markdown rendering.
Build the smallest useful site
This tutorial walks through the smallest complete shape that still reflects the framework's design:
markdown content under
content/a Rust site program under
crates/site/a build that writes static files into
dist/
If you have not looked around the repository yet, read Getting started first.
1. Add content
Create a file under content/blog/:
---
title: Hello world
date: 2026-03-28
tags:
- intro
---
This is my first post.
This gives the site one typed content entry to load from the blog collection.
2. Define the site in Rust
At its smallest, the site definition looks like this:
use maud::html;
use serde::Deserialize;
use site_core::{Artifact, Site};
#[derive(Clone, Debug, Deserialize)]
struct BlogPost {
title: String,
date: String,
}
fn build_site() -> site_core::Result<Site> {
Site::builder()
.content_dir("content")
.cache_dir(".site-cache")
.collection::<BlogPost>("blog")
.page("/", |ctx| {
let posts = ctx.collection::<BlogPost>("blog")?;
Ok(Artifact::Html(html! {
html {
body {
h1 { "Home" }
p { (format!("{} posts loaded", posts.len())) }
}
}
}))
})
.collection_page::<BlogPost, _>("blog", "/blog/{slug}/", |ctx, entry| {
let body = ctx.render_content(entry)?;
Ok(Artifact::Html(html! {
html {
body {
article {
h1 { (&entry.frontmatter.title) }
(body)
}
}
}
}))
})
.build()
}
There is no template DSL hiding the site structure. Collections, routes, and render behavior are ordinary Rust.
3. Build the site
Run:
cargo run -p site -- build
That command loads content, expands routes, renders artifacts, writes dist/, and updates .site-cache/.
4. Inspect the outputs
After the build:
open
dist/index.htmlopen
dist/blog/<slug>/index.htmlinspect
dist/assets/if the content referenced local media
On a second build, unchanged routes and asset transforms should be skipped or restored from cache.
5. Add the first conveniences
From here, most sites usually add three things:
custom markdown components
non-HTML routes such as
sitemap.xmlasset transforms for authored images
Those all stay explicit in Rust too.
Next steps
Use Generate non-HTML routes for XML, JSON, and flat files.
Use Build paginated sitemaps for generated route families.
Use Override markdown components when markdown tags need custom rendering.
Use Work with content images for source-format-agnostic asset requests.
Use Post-process routes and assets when output cleanup belongs outside route handlers.
Use Inspect build reports when your CLI or tests need to see what the build actually did.