Anna Documentation
Anna is a high-performance static site generator built in Go, designed for speed and simplicity. It features parallel rendering, live reload, responsive templates with support for collections, tags, and advanced Markdown features.
Command-Line Interface
Anna provides a powerful CLI for building and managing your site. Here are the available commands and flags:
Basic Usage
# Render the site
./anna
# Serve with live reload
./anna -s
# Show version
./anna -v
# Show help
./anna -h
Flags
-p, --path <path>- Specify the site directory (default:site/)-s, --serve- Serve the rendered site and watch for file updates with live reload-d, --draft- Include draft posts (pages withdraft: truein frontmatter)-a, --addr <addr>- Specify the address to serve on (default:localhost:8000)-v, --version- Print the current version and commit hash--prof- Enable profiling to measure rendering performance-h, --help- Show help message
Interactive Setup
If you don't have a site directory, Anna can help you set one up:
# Just run anna without a config and it will prompt you
./anna
Directory structure
Anna requires the following directory structure
site
├── content
│ ├── docs.md
│ ├── index.md*
│ ├── sub0folder
│ │ ├── bench.md
│ │ ├── building-anna
│ │ │ ├── images
│ │ │ │ ├── bench.png
│ │ │ │ └── wizard.gif
│ │ │ ├── index.md
│ │ └── weekly-progress
│ │ ├── week-1.md
│ │ ├── week-2.md
│ │ └── week-3.md
├── layout
│ ├── collection-subpage.html*
│ ├── collections.html*
│ ├── config.json*
│ ├── page.html*
│ ├── partials
│ │ ├── head.html
│ ├── robots.txt*
│ ├── tag-subpage.html*
│ |── tags.html*
│ ├── collection-subpage.html*
│ └── collections.html*
├── public
└── static
├── fonts
│ ├── VictorMono
│ │ └── victormono_italics.ttf
├── scripts
│ └── light.js
├── style.css
├── styles
└── tokyo.css
Files marked * are required and cannot be omitted
Description of the directory structure
- All of the site data, including the content, configuration and static files, are stores in site/. The rendered/ directory generated by ssg is also stored in
site/. - The markdown content for the site is stored in
content/. It can contain subdirectories along with images as the folder is recursively rendered.- The contents of this dir is rendered to the root of
rendered/
- The contents of this dir is rendered to the root of
- Static assets such as fonts are stored in
static/ - Scripts are stored in the
scripts/dir instatic/ - The layout of the site is configured using html files in
layout/- The
config.jsonfile stores the configuration of the site and includes details such as the baseURL - The
collections.html,collection-subpage.html,tags.htmland other necessary layouts define the structure of the various pages of the site such ascollections.html,collections/[[sub-page]].htmland other SSG generated pages - Additional layouts can be created and set for various pages of the site using the
layoutfrontmatter field - The layout files can be composed of smaller html files which are stored in the
partials/folder
- The
- Contents in
public/are rendered to the root ofrendered/
Building layouts
- Each layout file can access any data from the entire ssg
- The
tags.htmlpage can access the following data:{{.DeepDataMerge}}{{.PageURL}}{{.TemplateData}}{{.TagNames}}
- The remaining pages can access the following data
{{.DeepDataMerge}}{{.PageURL}}
PageURL
The {{.PageURL}} is of the form index.html, collections/tech/go.html and so on.
Elements stored in DeepDataMerge
{{.DeepDataMerge.Collections}}- A map that stores the template data of the collection sub-pages for a particular collection url{{.DeepDataMerge.CollectionsMap}}- A map that stores a slice of templates of all pages for a particular collection url{{.DeepDataMerge.JSONIndex}}- Stores the JSON index generated for a particular site (primarily used for search and graphing of tags){{.DeepDataMerge.LayoutConfig}}- Stores the layout parsed fromconfig.json{{.DeepDataMerge.Templates}}- A map that stores the template data of all the pages of the site for the particular url(the URL is the PageURL for the specified page){{.DeepDataMerge.Tags}}- A map that stores the template data of the tag sub-pages for a particular tag url{{.DeepDataMerge.TagsMap}}- A map that stores a slice of templates of all pages for a particular tag url
Layout Partials
Anna supports layout partials, which are reusable HTML template fragments stored in the layout/partials/ directory. Partials allow you to break down complex layouts into smaller, manageable pieces that can be shared across multiple layout files.
How Partials Work
Partials use Go's template system with the {{define}} and {{template}} directives:
- Defining a Partial: Use
{{define "partialName"}}to define a partial template - Including a Partial: Use
{{template "partialName" .}}to include the partial in a layout
Partials have access to the same data context as the main layout templates, including:
{{.DeepDataMerge}}- All site data{{.PageURL}}- Current page URL{{.TemplateData}}- Page-specific template data
Example Partial Structure
Here's how the built-in partials are organized:
layout/partials/
├── head.html # HTML head section with meta tags, stylesheets, and scripts
├── header.html # Site header with navigation and branding
├── footer.html # Site footer with copyright and links
└── search.html # Search modal/component
Creating and Using Partials
Example: Defining a partial in head.html
{{define "head"}}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{index .DeepDataMerge.Templates .PageURL | .Frontmatter.Title}}</title>
<!-- Additional head content -->
</head>
{{end}}
Example: Using partials in a layout file (page.html)
{{define "page"}}
{{template "head" .}}
<body>
{{template "header" .}}
<main>
<!-- Page content -->
{{index .DeepDataMerge.Templates .PageURL | .Body}}
</main>
{{template "footer" .}}
</body>
</html>
{{end}}
Best Practices for Partials
-
Naming Convention: Use descriptive names that match the partial's purpose (e.g., "head", "header", "footer")
-
Data Access: Always check if page data exists before accessing it:
{{$PageData := index .DeepDataMerge.Templates .PageURL}} {{if eq $PageData nil}} {{$PageData = .TemplateData}} {{end}} -
Modularity: Keep partials focused on a single responsibility
-
Reusability: Design partials to work across different layout types
-
Conditional Logic: Use template conditionals to show/hide content based on page data
Common Partial Patterns
- Head Section: Meta tags, stylesheets, scripts, and SEO data
- Navigation: Site-wide navigation menus and breadcrumbs
- Footers: Copyright notices, social links, and site information
- Components: Reusable UI components like search forms, modals, or sidebars
Partials make your layouts more maintainable by separating concerns and reducing code duplication across different page types.
Accessing specific page data
The URL for the current page can be accessed using {{.PageURL}}
To access the data for a particular page, use Go templating syntax:
{{$PageData := index .DeepDataMerge.Templates .PageURL}}
{{$PageData.CompleteURL}}
To access the page data for collections.html, tags.html and their respective partials, set
{{$PageData := .TemplateData}}
All of the following page data fields can be accessed in the above manner:
{{$PageData.CompleteURL}}: Returns the complete url of the given page{{$PageData.Date}}: Returns the last modified date of the current file{{$PageData.Frontmatter.[Tagname]}}: Returns the value of the frontmatter tag- Example:
{{$PageData.Frontmatter.Title}}: Returns the value of the title tag
- Example:
{{$PageData.Body}}: Returns the markdown body rendered to HTML
Custom template functions
Anna has the following pre-defined template function:
-
func strSliceContains(items []string, search string) boolThis function returns true if asearchstring is present in a slice of strings (items), else returns falseUsage:
{{if strSliceContains $PageData.Frontmatter.Collections "posts"}}
Frontmatter
All markdown content files must start with YAML frontmatter. Anna requires at minimum a title field, or it will throw an error.
Frontmatter is written as YAML between --- delimiters at the top of your markdown file:
---
title: "Your Page Title"
date: 2024-01-15
tags: ["golang", "web"]
collections: ["posts"]
---
Frontmatter Fields Reference
Required:
title- The page title (used in HTML<title>and navigation)
Optional Fields:
date- Publication date inYYYY-MM-DDformatdescription- Page description (meta tags, collection previews)authors- Array of author names:["Alice", "Bob"]tags- Array of topic tags:["golang", "web"]collections- Array of collection names:["posts", "featured"]draft- Set totrueto exclude from builds (unless-dflag used)layout- Custom layout template name (without.html)previewimage- URL to preview image for social sharingscripts- Array of page-specific JS files to includetoc- Set totrueto auto-generate table of contentscustomFields- Array of custom key-value pairs for template access
Frontmatter Examples
Basic Page Frontmatter
---
title: "My Blog Post"
date: 2024-01-15
description: "A brief description of this post"
authors: ["John Doe"]
tags: ["golang", "ssg"]
collections: ["posts"]
toc: true
---
Draft Post
---
title: "Work in Progress"
date: 2024-01-15
draft: true
---
Custom Layout
---
title: "Special Page"
layout: "custom-layout"
scripts:
- "/static/special.js"
---
Collection Page
---
title: "Building Anna: A Static Site Generator"
date: 2024-01-01
collections: ["posts", "anna"]
tags: ["golang", "static-site", "development"]
previewimage: "/static/images/anna-preview.png"
---
Complex Example with Multiple Authors and Custom Fields
---
title: "Collaborative Technical Article"
date: 2024-01-20
authors: ["Alice Smith", "Bob Johnson"]
description: "Deep dive into static site generation"
tags: ["golang", "performance", "web"]
collections: ["tutorials", "featured"]
toc: true
previewimage: "/static/preview.png"
scripts:
- "/static/scripts/interactive.js"
customFields:
- difficulty: "advanced"
readTime: "20 min"
topic: "architecture"
---
Accessing Frontmatter in Templates
Frontmatter values are accessible in layout templates through the Frontmatter field:
<!-- Access title -->
<h1>{{ $PageData.Frontmatter.Title }}</h1>
<!-- Access authors -->
{{range $PageData.Frontmatter.Authors}}
<p>Author: {{.}}</p>
{{end}}
<!-- Access tags -->
{{range $PageData.Frontmatter.Tags}}
<a href="/tags/{{.}}.html">{{.}}</a>
{{end}}
<!-- Conditional rendering -->
{{if $PageData.Frontmatter.Toc}}
<div class="toc">{{ $PageData.Body | toc }}</div>
{{end}}
Body & Markdown
Anna uses Goldmark to render markdown files, which is fully CommonMark compliant. This means your markdown works across different platforms and tools.
Markdown Extensions
Anna includes several powerful Goldmark extensions for enhanced functionality:
Anchors
The anchor extension automatically adds linkable anchor elements next to all headings:
## Getting Started
<!-- Renders with automatic anchor: https://example.com/page.html#getting-started -->
Figures
The figure extension converts images in paragraphs to HTML <figure> elements for semantic markup and better styling:

<!-- Renders as: <figure><img src="..."/></figure> -->
Table of Contents
The toc extension enables automatic table of contents generation. Enable with frontmatter:
---
title: "Long Article"
toc: true
---
This generates a clickable table of contents from all <h2> and <h3> headings in the page.
Markdown Best Practices
- Use semantic headings - Start with H1 (one per page), then H2, H3, etc.
- Keep paragraphs short - Easier to read and understand
- Use code blocks with syntax highlighting - Specify language:
```gofor Go,```htmlfor HTML, etc. - Include alt text for images - Important for accessibility and SEO
- Use emphasis wisely - Prefer italics over underscores for consistency
Static assets
Static files like stylesheets, scripts, images, and fonts are served without modification. Anna supports multiple asset directories:
Asset Directories
static/- Global static assets (recommended)- Copied to
rendered/static/ - Use for CSS, JS, fonts, reusable images
- Reference as
/static/...
- Copied to
content/- Content-local assets- Images alongside markdown files
- Automatically copied to
rendered/ - Use for post-specific images and diagrams
public/- Root-level assets- Copied directly to
rendered/ - Use for robots.txt, favicon.ico, .well-known files
- Reference from root:
/file.txt
- Copied directly to
Images
Reference images in your markdown with absolute paths:
<!-- Global image -->

<!-- Post-specific image (in content/posts/) -->

<!-- Root-level image -->

CSS
Add stylesheets to your layout files:
<!-- External stylesheet in static/ -->
<link rel="stylesheet" href="/static/styles/main.css">
<!-- Inline styles -->
<style>
body { font-family: sans-serif; }
</style>
<!-- Inline on elements -->
<div style="color: red;">Error message</div>
Set the global theme in config.json:
{
"themeURL": "/static/styles/theme.css"
}
JavaScript
Include scripts in layouts or pages:
<!-- Global scripts in layout files -->
<script src="/static/scripts/analytics.js"></script>
<!-- Page-specific scripts via frontmatter -->
Frontmatter:
scripts:
- "/static/scripts/interactive.js"
- "/static/scripts/widgets.js"
Fonts
Store font files in static/fonts/:
<style>
@font-face {
font-family: 'CustomFont';
src: url('/static/fonts/custom-font.ttf');
}
</style>
Asset Organization Best Practices
site/static/
├── styles/
│ ├── main.css
│ ├── theme.css
│ └── components/
│ ├── button.css
│ └── card.css
├── scripts/
│ ├── app.js
│ └── utils/
│ ├── helpers.js
│ └── api.js
├── images/
│ ├── logo.png
│ ├── icons/
│ └── backgrounds/
└── fonts/
├── opensans.ttf
└── roboto.ttf
Development Workflow
Building the Site
Anna provides several ways to build and serve your site:
Basic Build
# Build the site once
anna
# Build with drafts included
anna -d
# Build and serve locally
anna -s
# Build and serve with drafts
anna -s -d
Using Make
The included Makefile provides convenient build targets:
# Build the site
make build
# Clean build artifacts
make clean
# Run tests
make tests
# Serve the site with live reload
make serve
Live Reloading
When running with the -s flag, Anna includes live reload functionality:
- The server watches for file changes in
content/,layout/, andstatic/ - When changes are detected, the site is automatically rebuilt
- Connected browsers automatically refresh to show changes
- Live reload scripts are injected into pages during development
File Watching
Anna monitors the following directories for changes:
content/- Markdown files and assetslayout/- HTML templates and partialsstatic/- Static assets (CSS, JS, images)site/config.json- Site configuration
Changes to any files in these directories trigger a rebuild.
Advanced Features
Custom Frontmatter Fields
Beyond the built-in frontmatter fields, you can add custom fields to support your specific needs:
---
title: "Advanced Topics"
customFields:
- category: "Tutorial"
difficulty: "advanced"
readTime: "15 min"
- prerequisites:
- "golang-basics"
- "web-development"
---
Access custom fields in templates:
{{range $PageData.Frontmatter.CustomFields}}
{{range $key, $value := .}}
<span>{{$key}}: {{$value}}</span>
{{end}}
{{end}}
Multiple Authors
Track multiple authors for collaborative content:
---
title: "Collaborative Post"
authors: ["Alice", "Bob", "Charlie"]
---
Display in templates:
<div class="authors">
By: {{range $PageData.Frontmatter.Authors}}{{.}}{{end}}
</div>
Page-Level Scripts
Add scripts that run only on specific pages:
---
title: "Interactive Demo"
scripts:
- "/static/scripts/interactive.js"
- "/static/scripts/visualization.js"
---
These scripts are injected into the page in your layout:
{{range $PageData.Frontmatter.JSFiles}}
<script src="{{.}}"></script>
{{end}}
Nested Collections
Group content hierarchically:
---
title: "Getting Started with Golang"
collections: ["tutorials", "golang-101", "beginner-friendly"]
---
This creates:
collections/tutorials.htmlcollections/golang-101.htmlcollections/beginner-friendly.html
Live Reload Script Injection
During development (when using -s), Anna automatically injects a live reload script. This script:
- Watches for server-side changes
- Automatically reloads the browser
- Is removed in production builds
JSON Index Structure
The generated index.json contains searchable metadata:
{
"index.html": {
"title": "Home",
"url": "/index.html",
"tags": ["home"],
"description": "Welcome to my site",
"authors": ["Admin"],
"date": 1234567890
},
"posts/golang-tutorial.html": {
"title": "Learning Golang",
"url": "/posts/golang-tutorial.html",
"tags": ["golang", "tutorial"],
"description": "A beginner's guide to Golang",
"authors": ["Expert"],
"date": 1234567890
}
}
You can use this in client-side search implementations:
// Fetch the index
fetch('/index.json')
.then(r => r.json())
.then(index => {
// Implement search using this index
});
Profiling and Performance Analysis
Run Anna with profiling to identify performance bottlenecks:
anna --prof
This generates profiling data that shows:
- Rendering time per page
- Template processing time
- Markdown parsing time
- File I/O time
Collections & Tags
Anna supports two powerful organizational features for grouping content: Collections and Tags.
Collections
Collections allow you to organize related content (e.g., blog posts, documentation, tutorials) into separate sections of your site.
Creating Collections
Add collections frontmatter to your pages:
---
title: "My Blog Post"
collections: ["posts", "featured"]
---
Automatic Collection Pages
Anna automatically generates:
collections.html- Lists all collection categoriescollections/[collection-name].html- Dedicated page for each collectioncollections/[collection-name]/[page-name].html- Individual collection sub-pages
Configuring Collection Layouts
Specify custom layouts for collection pages in config.json:
{
"collectionLayouts": {
"collections/posts.html": "all-posts",
"collections/tutorials.html": "tutorials-layout"
}
}
Tags
Tags provide fine-grained categorization of content and enable topic-based navigation.
Adding Tags
Add tags frontmatter to your pages:
---
title: "Getting Started with Go"
tags: ["golang", "beginner", "tutorial"]
---
Automatic Tag Pages
Anna automatically generates:
tags.html- Cloud view of all tags with frequencytags/[tag-name].html- Pages for each individual tag- Filtered content on each tag page
Using Tags in Templates
<!-- Link to a tag page -->
{{range $PageData.Frontmatter.Tags}}
<a href="/tags/{{.}}.html">{{.}}</a>
{{end}}
<!-- Check if a page has a specific tag -->
{{if strSliceContains $PageData.Frontmatter.Tags "featured"}}
<span class="featured-badge">Featured</span>
{{end}}
Site Generation
Automatic File Generation
When you run Anna, it automatically generates several files in the rendered/ directory:
Sitemap
rendered/sitemap.xml - XML sitemap for search engines containing all pages, their modification dates, and change frequency.
RSS/Atom Feed
rendered/feed.xml - Atom feed with recent pages for RSS readers (sorted by date, latest first)
JSON Index
rendered/index.json - Searchable index of all pages with metadata:
- Page titles
- URLs
- Tags
- Description
- Preview images
- Authors
This is useful for building search functionality on your site.
Robots.txt
rendered/robots.txt - Web crawler directives (copied from layout/robots.txt)
Site configuration
The config.json file stores configuration for your site's layout and behavior. It's located in site/layout/config.json and is required.
Configuration Fields
navbar- Array of navigation links (format:[{"Label": "path/to/page.html"}])baseURL- Base URL of your site (used for sitemaps, feeds, SEO; no trailing slash)siteTitle- Title of your websitesiteScripts- Global JavaScript files to include on all pagesauthor- Default author namecopyright- Copyright notice for your sitethemeURL- URL to your main stylesheet (e.g.,/static/style.css)socials- Social media links (format:{"twitter": "https://twitter.com/...", ...})collectionLayouts- Map collection URLs to custom layout templatescustomFields- Additional arbitrary key-value pairs for your layouts
Complete Example
{
"navbar": [
{"Home": "index.html"},
{"Blog": "collections/posts.html"},
{"Tags": "tags.html"},
{"About": "about.html"}
],
"baseURL": "https://example.com",
"siteTitle": "My Awesome Site",
"siteScripts": [
"/static/scripts/analytics.js",
"/static/scripts/search.js"
],
"author": "Jane Doe",
"copyright": "Copyright 2024. All rights reserved.",
"themeURL": "/static/styles/main.css",
"socials": {
"github": "https://github.com/yourname",
"twitter": "https://twitter.com/yourname",
"email": "you@example.com"
},
"collectionLayouts": {
"collections/posts.html": "posts-layout",
"collections/tutorials.html": "tutorials-layout"
},
"customFields": [
{
"company": "Acme Corp",
"supportEmail": "support@example.com"
}
]
}
SEO Configuration
The baseURL field is critical for SEO:
- Used in
sitemap.xmlto generate absolute URLs - Included in
feed.xmlfor RSS readers - Used for canonical URLs in metadata
- Helps search engines discover and index your site
Example with baseURL: "https://example.com"
- Sitemap links:
https://example.com/posts/index.html - Feed links:
https://example.com/about.html
Best Practices
Content Organization
- Use Collections for major sections - e.g., blog posts, documentation, tutorials
- Use Tags for topics - e.g., "golang", "web-development", "performance"
- Keep frontmatter consistent - Set common fields across related pages
- Use meaningful filenames - e.g.,
getting-started-with-go.mdrather thanpost1.md
Performance Optimization
- Minimize custom frontmatter fields - Only add what you need
- Optimize images - Compress images before adding to
static/ - Defer non-critical scripts - Use
deferattribute in layout partials - Leverage live reload - Use
-sflag during development for fast iteration
Template Design
-
Use partials for reusable components - e.g., headers, footers, sidebars
-
Keep layouts DRY - Don't repeat HTML across multiple templates
-
Check data existence - Use Go template conditionals:
-
Use semantic HTML - For better SEO and accessibility
{{if $PageData.Frontmatter.PreviewImage}} <img src="{{$PageData.Frontmatter.PreviewImage}}" /> {{end}}
Asset Management
- Static assets in
static/- Stylesheets, JavaScript, fonts - Images in
content/- Keep images with related markdown - Keep directory flat - Avoid deep nesting in
static/ - Reference with absolute paths - e.g.,
/static/images/logo.png
SEO Optimization
- Set meaningful titles - Use descriptive, keyword-rich titles
- Write descriptions - Add
descriptionfrontmatter for snippets - Add preview images - Use
previewimagefor social sharing - Use keywords in tags - Make tags searchable and relevant
- Structure with headings - Use proper heading hierarchy for accessibility
- Enable table of contents - Use
toc: truefor long-form content
