Pages
Pages are Markdown files that become HTML pages on your site. This page covers how to write content — front matter fields, Markdown syntax, and file organization. For how these fields are accessed in templates, see the Data Model.
Basic Structure
+++
title = "My Page"
date = "2024-01-15"
+++
Your content in **Markdown**.
The +++ block is TOML front matter. Content below becomes HTML.
Front Matter
Required
| Field | Type | Description |
|---|---|---|
| title | string | Page title |
Common Fields
| Field | Type | Default | Description |
|---|---|---|---|
| date | string | — | Publication date (YYYY-MM-DD) |
| description | string | — | SEO description |
| draft | bool | false | Exclude from production builds |
| template | string | "page" | Template to use |
| weight | int | 0 | Sort order (lower = first) |
| image | string | — | Featured image for social sharing |
| tags | array | [] | Tag taxonomy terms |
| categories | array | [] | Category taxonomy terms |
All Fields
| Field | Type | Description |
|---|---|---|
| updated | string | Last updated date |
| slug | string | Custom URL slug |
| path | string | Custom URL path |
| aliases | array | Redirect URLs to this page |
| authors | array | Author names |
| toc | bool | Show table of contents |
| in_search_index | bool | Include in search |
| in_sitemap | bool | Include in sitemap |
| insert_anchor_links | bool | Add heading anchors |
| redirect_to | string | Redirect page to this URL |
| render | bool | Render page to output (default: true) |
| expires | date | Auto-exclude after this date |
| series | string | Series name for grouping |
| series_weight | int | Sort order within series |
| extra | table | Custom metadata |
Examples
Blog Post
+++
title = "Getting Started with Crystal"
date = "2024-01-15"
description = "Learn Crystal programming basics"
tags = ["crystal", "tutorial"]
authors = ["Alice Smith"]
image = "/images/crystal-guide.png"
+++
Crystal is a fast, compiled language...
Draft
+++
title = "Work in Progress"
draft = true
+++
Not visible in production.
Build with drafts: hwaro build --drafts
Expiring Content
+++
title = "Limited Time Offer"
expires = 2025-12-31
+++
Automatically excluded from builds after the expiry date.
Build with expired content: hwaro build --include-expired
Pages expiring within 7 days generate a build warning.
Future-Dated Content
Pages with a date in the future are automatically excluded from builds. This is useful for scheduling content.
+++
title = "Coming Soon"
date = 2099-01-01
+++
Published only after the date arrives.
Build with future content: hwaro build --include-future
Series Post
+++
title = "Part 1: Introduction"
series = "Crystal Tutorial"
series_weight = 1
+++
First part of the series.
In templates, access page.series, page.series_index, and page.series_pages.
Custom Template
+++
title = "Landing Page"
template = "landing"
+++
Uses `templates/landing.html` instead of `page.html`.
Weighted Order
+++
title = "Introduction"
weight = 1
+++
+++
title = "Getting Started"
weight = 2
+++
Lower weight appears first.
URL Aliases
+++
title = "New Page"
aliases = ["/old-url/", "/another-old-url/"]
+++
Redirects from old URLs to this page.
Custom Metadata
+++
title = "Product Review"
[extra]
rating = 4.5
featured = true
pros = ["Fast", "Reliable"]
+++
Access in templates: {{ page.extra.rating }}
Full Front Matter Reference
All available fields in one block. Copy and remove what you don't need.
+++
title = "Page Title"
date = "2024-01-15"
updated = "2024-02-01"
description = "SEO description"
draft = false
template = "page"
weight = 0
slug = "custom-slug"
path = "custom/path"
aliases = ["/old-url/"]
image = "/images/cover.png"
tags = ["tag1", "tag2"]
categories = ["category1"]
authors = ["Author Name"]
toc = true
in_search_index = true
in_sitemap = true
insert_anchor_links = true
render = true
redirect_to = ""
expires = 2025-12-31
series = "Series Name"
series_weight = 1
[extra]
custom_field = "value"
+++
Content Summary
Use <!-- more --> to define a summary:
+++
title = "Long Article"
+++
This is the summary shown in listings.
<!-- more -->
The full article continues here...
Markdown Syntax
Text
**bold** and *italic*
`inline code`
[link](https://example.com)

Lists
- Unordered
- Items
1. Ordered
2. Items
Code Blocks
```javascript
console.log("Hello");
```
Tables
<table>
<thead>
<tr>
<th>Header</th>
<th>Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell</td>
<td>Cell</td>
</tr>
</tbody>
</table>
Table cells support inline Markdown: bold, italic, code spans, links, , and ~~strikethrough~~.
<table>
<thead>
<tr>
<th>Feature</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bold</td>
<td><strong>important</strong></td>
</tr>
<tr>
<td>Italic</td>
<td><em>emphasis</em></td>
</tr>
<tr>
<td>Code</td>
<td><code>config.toml</code></td>
</tr>
<tr>
<td>Link</td>
<td><a href="https://example.com">Hwaro</a></td>
</tr>
<tr>
<td>Image</td>
<td><img src="/img/logo.png" alt="logo"></td>
</tr>
<tr>
<td>Strikethrough</td>
<td><del>deprecated</del></td>
</tr>
</tbody>
</table>
Internal Links
Use @/ to link to other content pages by their source path. Hwaro resolves these to the correct output URL at build time.
[Read the post](@/blog/my-post.md)
[About section](@/about/_index.md)
[With anchor](@/blog/my-post.md#introduction)
This is useful because you don't need to know the final URL — Hwaro calculates it from the content path. If the target page doesn't exist, the link is left unchanged and a warning is logged during build.
| Syntax | Resolved URL |
|---|---|
@/blog/post.md |
/blog/post/ |
@/blog/_index.md |
/blog/ |
@/blog/post.md#section |
/blog/post/#section |
Blockquotes
> Quote text
Asset Colocation
You can keep related assets (images, PDFs, etc.) in the same directory as your content file. This is known as a Page Bundle.
To use this feature, rename your markdown file to index.md (for regular pages) or _index.md (for section pages) and place it in a directory named after your page.
Example Structure:
content/
└── blog/
├── my-trip/
│ ├── index.md <-- The page content
│ ├── photo.jpg <-- Asset
│ └── data.json <-- Asset
└── _index.md
Hwaro will copy all non-markdown files from the page bundle directory to the output directory, maintaining the relative path.
In your markdown, you can link to these assets using relative paths:

[Download Data](data.json)
Accessing Assets in Templates
You can access the list of colocated assets in your templates using page.assets. This returns an array of relative paths to the files.
{% for asset in page.assets %}
{% if asset is matching("[.](jpg|png)$") %}
<img src="{{ get_url(path=asset) }}" alt="Gallery Image">
{% endif %}
{% endfor %}
URL Mapping
| File | URL |
|---|---|
| content/index.md | / |
| content/about.md | /about/ |
| content/blog/post.md | /blog/post/ |
See Also
- Sections — Group related pages
- Data Model — Page properties in templates