Content Overview
Content in Alloy lives in the content/ directory. Each file with a supported extension (.md, .html by default) becomes a page on your site. Alloy reads the front matter, applies the data cascade, renders the body, wraps it in a layout, and writes the result to _site/.
content/
├── index.md # → _site/index.html (site root)
├── about.html # → _site/about/index.html
└── blog/
├── _data.yaml # Directory-level data (cascades to all blog pages)
├── index.md # → _site/blog/index.html
├── first-post.md # → _site/blog/first-post/index.html
└── second-post/ # Page bundle (co-located assets)
├── index.md # → _site/blog/second-post/index.html
└── hero.jpg # Copied to _site/blog/second-post/hero.jpg
Supported content formats
The content.formats config controls which file extensions are treated as content. The default is ["md", "html"]:
# alloy.config.yaml
content:
formats: ["md", "html"]
Files matching these extensions go through the full pipeline: front matter extraction, data cascade, template rendering, and layout wrapping. Everything else in content/ is treated as a passthrough file and copied to the output as-is.
Front matter is required
Every content file must start with front matter delimiters. Alloy supports YAML (---), TOML (+++), and JSON ({}):
---
title: "My First Post"
date: 2026-04-10
tags: ["tutorial", "getting-started"]
---
This is the body of the post. It supports **Markdown**, Liquid template
tags like {{ site.title }}, and raw HTML.
Empty front matter is valid – use --- followed by --- on the next line when you have no metadata to set. Files without any front matter delimiters produce a build error.
How content is processed
Every content file passes through a multi-stage pipeline:
- Discovery – Alloy walks the
content/directory and identifies content files by extension. - Front matter extraction – Metadata is parsed from the top of each file.
- Data cascade – Global data, directory data (
_data.yaml), and front matter are merged. See Data Cascade. - Permalink resolution – The output URL is computed from front matter, cascade patterns, or the file path. See Permalinks.
- Content rendering – Markdown is converted to HTML. Template tags (
{{ }},{% %}) are evaluated. - Layout wrapping – The rendered content is injected into a layout template as
{{ content }}. - Output – The final HTML is written to
_site/.
For a deeper look at each stage, see Content Lifecycle.
Markdown configuration
Alloy uses goldmark for Markdown rendering. Configure it in alloy.config.yaml:
content:
markdown:
goldmark:
unsafe: true # Allow raw HTML in Markdown (default: false)
typographer: true # Smart quotes and dashes
templateTags: true # Preserve {{ }} and {% %} through Markdown (default: true)
autoHeadingID: true # Add id attributes to headings (default: true)
toc: true # Generate page.toc data (default: true)
With templateTags: true (the default), Liquid and Go template syntax passes through the Markdown parser untouched. You can mix Markdown and template logic in the same file without escaping.
HTML content files
.html files in content/ are classified based on their content:
- Has front matter – Processed as a content page, same as Markdown.
- No front matter + starts with
<!DOCTYPEor<html>– Treated as a full HTML document and copied to output as-is (passthrough). - No front matter + no DOCTYPE – Treated as an HTML fragment. The file body becomes the page content with empty front matter, inheriting its layout from the
_data.yamlcascade.
This classification lets you co-locate standalone HTML documents alongside templated content without adding front matter to every file.
Co-located assets
Non-content files inside content/ are automatically copied to the output, preserving their relative path. This enables page bundles where a post and its images live together:
content/blog/my-post/
├── index.md # Content file → _site/blog/my-post/index.html
├── diagram.svg # Passthrough → _site/blog/my-post/diagram.svg
└── hero.png # Passthrough → _site/blog/my-post/hero.png
Reference co-located assets with relative paths in your Markdown: .
Custom directory structure
Override the default content/ path in config:
# alloy.config.yaml
structure:
content: "./docs/pages/"
All pipeline stages, the file watcher, and the dev server respect the configured path.
What to read next
- Front Matter – All available front matter fields
- Data Cascade – How global, directory, and page data merge
- Permalinks – URL patterns and tokens
- Pagination – List pages and virtual page generation
- Content Lifecycle – Draft, future, and expired content
- Data Files – Global data from
data/and external sources