Documentation · Getting Started · Blog
A static site generator written in Go. Drop in Markdown, get a themed site. Ideal for product or API documentation, course materials, and blogs; conventions handle the structure, so the config file stays a few lines long.
Sarde is a single Go binary with no runtime dependencies, and your directory structure is the site structure. Put files in content/docs/ and you get sidebar navigation, versioning, a table of contents, and search. A content/blog/ directory produces a date-sorted blog with RSS. Both layouts are selected by directory name alone, without additional configuration.
Defaults can be overridden through sarde.yaml, CLI flags, or environment variables.
Content
- Auto-detected collections: directory names select docs layouts with sidebar and ToC, date-sorted blogs, lab guides, or slide decks (see the table under Project structure)
- Versioned docs (Docusaurus-style) with URL shadowing for the latest version
- Optional
sidebar.yamlfor per-path sidebar overrides, tab overrides, andcollapse_level - i18n with per-language directories, RTL support, and translation fallback
- Title, date, and sidebar order inferred automatically from filenames, headings, and git history
- Frontmatter in YAML, TOML, or JSON
- Page bundles (directory with
index.md+ images) with automatic responsive image generation
Markdown
- 30+ Goldmark extensions: code blocks with syntax highlighting (Kazari + Nuri), KaTeX math, Mermaid diagrams, GitHub-style alerts, callouts, cards, tabs, multi-column layouts, accordions, file trees, timelines, image comparison, keyboard shortcuts, spoilers, and more
- Syntax highlighting via Kazari (Expressive Code-style frames, diff markers, line numbers) powered by Nuri (TextMate grammars, 257 languages)
Asset pipeline
- CSS/JS bundling via esbuild (Go API, no Node.js)
- Image processing: resize, crop, WebP conversion, LQIP blur-up placeholders (AVIF is available, but only in builds compiled with
-tags avif; release binaries skip AVIF variants with a warning) - Content-hash fingerprinting for cache busting
- HTML/CSS/JS minification
Built-in plugins (13 enabled by default)
sitemap,robots,rss,atomfor standard web outputsseofor Open Graph and Twitter Card meta tagssocial_cardsfor server-side OG image generationsearchfor offline full-text search (Orama)link_validatorfor internal/external broken link detectioncontent_lintfor heading structure, image alt text, and frontmatter validationkatex,mermaidfor math and diagram asset injectionredirectsfor redirect stubs (HTML or Netlify_redirects)llms_txtfor LLM-friendly site index
Client-side plugins (11 available, all opt-in)
Add any of these to plugins.enabled to bundle its CSS and JS. Nothing ships to the browser unless it is listed, and each one is injected only on pages that need it.
scroll_to_top, copy_section_link, external_links, image_lightbox, keyboard_nav, focus_mode, reading_progress, search_highlighter, text_highlighter, reading_position_memory, reading_preferences
External plugins
- Install third-party plugins into
plugins/{slug}/withsarde plugin install, from a zip, directory, URL, or GitHub repo - Plugins are declarative (
plugin.yamlmanifest, assets, templates), so installing one never executes third-party code at build time plugins.disabledturns off any plugin, built-in or external, without replacing the wholeplugins.enabledlist- Premium plugins are unlocked by an offline ed25519-signed license file (
sarde license install). A missing or invalid license warns and skips the plugin; it never fails the build - The plugin manifest and license file formats are provisional for 1.0 and may change in a 1.x release
Developer experience
- Dev server with WebSocket live reload and incremental rebuilds
- Link checking with terminal, JSON, and GitHub Actions annotation output
- Content validation without building (
sarde validate) - Fenced-block syntax checking (
sarde check-syntax) - Merged configuration inspection with provenance (
sarde effective-config) - Obsidian vault importer (converts wikilinks and callouts)
- Deploy command for GitHub Pages, or any custom command (rsync, provider CLIs) via the
customprovider
Homebrew (macOS/Linux):
brew install getsarde/sarde/sardeShell script (macOS/Linux):
curl -sSfL https://raw.githubusercontent.com/getsarde/sarde/main/install.sh | shBinary download:
Grab the latest release from GitHub Releases. Available for Linux (amd64), macOS (amd64, arm64), and Windows (amd64).
From source:
go install github.com/getsarde/sarde/cmd/sarde@latest# Create a new site
sarde new site my-site
cd my-site
# Add some content
mkdir -p content/docs
echo '---
title: Getting Started
---
# Hello
This is your first page.' > content/docs/getting-started.md
# Start the dev server
sarde devOpen http://localhost:4727. The docs/ directory is auto-detected as a docs collection, so you get a sidebar, table of contents, and prev/next navigation out of the box.
To build for production:
sarde buildOutput goes to dist/ by default.
my-site/
content/ # Your Markdown files (required)
blog/ # Auto-detected as blog collection
docs/ # Auto-detected as docs collection
_index.md # Homepage content (optional)
public/ # Copied as-is to output
icons/ # Local SVG icons
themes/ # Custom themes (optional)
plugins/ # Installed external plugins (optional)
sarde.yaml # Configuration (optional)
sidebar.yaml # Sidebar overrides (optional)
kazari.config.yaml # Code block presentation (optional)
Collections are detected by directory name:
| Directory names | Type | Default sort | Layout |
|---|---|---|---|
blog, posts, articles, news |
Blog | date descending | Feed with pagination |
docs, documentation, guides, reference, courses, tutorials, lessons, workshops |
Docs | sidebar.order ascending |
Three-column with sidebar + ToC |
labs |
Labs | sidebar.order ascending |
Lab guide with progress and objectives |
slides, presentations, decks |
Slides | date descending | Presentation deck with gallery landing |
| Anything else | Generic | title ascending | Default |
These names are a convention, not a requirement. Any directory name works, and an unrecognized name becomes a generic collection. To get docs behavior under a different name, set it explicitly under collections: in sarde.yaml rather than renaming the directory.
All configuration goes in sarde.yaml. Every option has a sensible default; the file is entirely optional. Values are resolved in a 5-layer cascade (last wins):
- Embedded defaults (compiled into the binary)
theme.yamlfrom the active themesarde.yamlin your project root- CLI flags (
--baseURL,--drafts,--future) - Environment variables (
SARDE_SITE_TITLE,SARDE_BUILD_OUTPUT, etc.)
Here is a minimal configuration:
site:
title: My Project
url: https://example.com
theme:
dark: trueAnd a more complete example:
site:
title: My Project
url: https://example.com
description: Project documentation and blog
edit_url: https://github.com/user/repo/edit/main/content
theme:
preset: docs
dark: true
build:
minify: true
last_updated: git # "git", "mtime", or "false"
collections:
docs:
versioning:
enabled: true
last_version: v2
versions:
- id: v2
label: v2.x (latest)
- id: v1
label: v1.x
i18n:
default_language: en
languages:
en:
name: English
fr:
name: Français
plugins:
# Listing `enabled` replaces the default set, so name every plugin you want.
enabled:
- sitemap
- rss
- search
- seo
- link_validator
- scroll_to_top # client-side plugins are opt-in
# `disabled` turns off individual plugins without replacing the list above.
disabled:
- social_cardsSee the default configuration for every available option and its default value.
sarde build # Build for production
sarde dev # Dev server with live reload (port 4727)
sarde new site <path> # Scaffold a new project
sarde new <collection> <title> # Add a page to a collection
sarde new course <name> # Create a course directory
sarde new lesson <course> <name> # Add an auto-numbered lesson
sarde check-links # Validate links without building
sarde check-syntax # Check fenced-block syntax
sarde validate # Validate config and content
sarde effective-config # Print merged config with provenance
sarde deploy # Deploy to configured provider
sarde theme list|add|remove|eject # Manage themes
sarde theme info|chromastyles # Inspect a theme, dump Chroma styles
sarde plugin list|install|remove|info # Manage external plugins
sarde license install|list # Manage premium plugin licenses
sarde icons add|list # Download/list Iconify icon sets
sarde i18n add-language|status # Manage languages (also remove-language, scaffold)
sarde doc-version create|delete|update # Manage docs versions
sarde import obsidian <vault> # Import an Obsidian vault
sarde update # Self-update the binary
sarde version # Print version infoGlobal flags: --config/-c, --baseURL, --drafts/-D, --future, --verbose/-v, --quiet/-q
Three layers:
- Interface: the CLI (Cobra) drives everything through ProjectManager, a unified API over the engine rather than direct file access
- Engine: seven-phase pipeline: Initialize, Discover, Parse (parallel), Assemble, Assets, Render (parallel), Write
- Plugins: four lifecycle hooks run in order: ConfigSetup (serial), ContentLoaded (serial), BeforeRender (serial per page), BuildDone (parallel)
The engine is designed around Go interfaces (ContentDiscoverer, FrontmatterParser, MarkdownRenderer, TemplateEngine) so each pipeline stage is independently testable.
# Development build
go build -o dist/sarde ./cmd/sarde
# With version tag
go build -ldflags "-X github.com/getsarde/sarde/internal/version.Version=1.0.0" -o dist/sarde ./cmd/sarde
# Cross-compile
GOOS=linux GOARCH=amd64 go build -o dist/sarde-linux ./cmd/sarde
GOOS=darwin GOARCH=arm64 go build -o dist/sarde-macos ./cmd/sarde
# Tests
go test ./...
# Benchmarks (in-process, over synthetic sites)
go test -bench=. -benchmem -timeout 300s ./internal/build/On Windows, build.bat wraps these commands: build.bat build, build.bat test, build.bat release.
For end-to-end build benchmarks (median wall time over a generated ~1,000 page fixture, pages/sec, per-phase timings, peak RSS, and an optional Hugo comparison), see benchmarks/README.md.
Current baseline (GitHub Actions ubuntu-latest, cold cache, median of 5 runs over the generated ~1,000 file fixture, 2,041 built pages):
| Metric | Value |
|---|---|
| Median wall time | 35.1 s |
| Pages/sec | 58 |
| Peak RSS | 931 MB |
The numbers come from benchmarks/baseline.json, seeded from CI. Methodology, per-phase timings, and the update procedure are in benchmarks/README.md.
- Core: Go, Goldmark, Cobra, Chroma v2, esbuild (Go API), fsnotify, go:embed
- Generated sites: Pure HTML/CSS with ~1KB inline JS, no framework runtime
- Search: Orama (offline, embedded in output)
- Minification: tdewolff/minify (HTML), esbuild (CSS/JS)
Contributions are welcome. Please open an issue to discuss significant changes before submitting a pull request.
# Clone and build
git clone https://github.com/getsarde/sarde.git
cd sarde
go build ./cmd/sarde
# Run tests
go test ./...
# Test against the example site
cd testsite/general
../../sarde devSarde's docs collection offers feature parity with Docusaurus and Starlight, whose conventions inspired it. The code block rendering is powered by Kazari, a Go port of Expressive Code.
MIT
Documentation: getsarde.github.io/sarde | Default config reference: sarde.yaml