# Zas — full documentation
Source: https://github.com/darccio/zas/tree/3868cbc501fbce52f4cc51183bef0c39f37e17e3/docs
License: AGPL-3.0-or-later (https://dario.cat/zas/LICENSE.txt). Each section identifies its Markdown URL for resolving relative links.
---
Source: https://dario.cat/zas/index.md
# Zas
Zas is a static site generator written in Go. It walks a site's files, renders Markdown and HTML through a shared layout, and copies ordinary assets into the deploy directory. The source directory structure becomes the site's URL structure.
## Install and start
The current source requires Go 1.26 or newer.
```sh
go install github.com/darccio/zas/cmd/zas@latest
mkdir my-site
cd my-site
zas init
```
Write `index.md`, edit `.zas/layout.html`, and build:
```sh
zas -full
```
The generated site is in `.zas/deploy` by default. Upload that directory to your static host.
`zas init` preserves an existing configuration and layout. `zas init -force` replaces both with scaffolded defaults.
These guides describe the current source. For reproducible builds, install a selected release tag or commit instead of `@latest`, and choose a revision containing the features you use.
## Guides
- [Configuration](configuration.md): site settings, page overrides and languages.
- [Templates and plugins](templates.md): layouts, metadata, embeds and the trust model.
- [Publishing](publishing.md): sitemaps, RSS, Markdown twins and deployment.
## Project links
- [Source repository](https://github.com/darccio/zas)
- [API reference](https://pkg.go.dev/github.com/darccio/zas)
- [Releases](https://github.com/darccio/zas/releases)
- [Report a bug](https://github.com/darccio/zas/issues)
- [Sponsor maintenance](https://github.com/sponsors/darccio)
Zas retains its module path `github.com/darccio/zas`. Hosting these guides on dario.cat does not change how Go users install or import it.
## License
Zas and these docs are distributed under the [GNU Affero General Public License, version 3](LICENSE.txt), or any later version.
---
Source: https://dario.cat/zas/configuration.md
# Configuration
Zas reads `.zas/config.yml`. You can keep the defaults and add only the settings your site needs.
```yaml
zas:
layout: .zas/layout.html
deploy: .zas/deploy
allowed_dotdirs: [".well-known"]
site:
baseurl: https://example.com
language: en
image: https://example.com/static/avatar.webp
sitemap: true
publish_markdown: true
```
## Site settings
| Setting | Default | Purpose |
| --- | --- | --- |
| `zas.layout` | `.zas/layout.html` | Shared HTML layout. |
| `zas.deploy` | `.zas/deploy` | Generated output directory. |
| `zas.allowed_dotdirs` | Empty | Specific top-level dot-directories to publish. |
| `site.baseurl` | `http://example.com` | Absolute site URL used by URL helpers, sitemaps and feeds. |
| `site.language` | `en` | Default page language. |
| `site.image` | Unset | Site image available through `.Site.Image`. |
| `site.sitemap` | `false` | Generate a sitemap and its robots directive. |
| `site.publish_markdown` | `false` | Publish rendered Markdown twins. |
| `site.feed` | `false` | Generate RSS feeds. |
Use a real HTTP(S) `baseurl` when generating a sitemap or feed. See [Publishing](publishing.md) for feed options and output behavior.
Dot-files and dot-directories are skipped by default. `allowed_dotdirs` accepts exact top-level names, such as `.well-known`; it does not allow nested dot-directories or patterns. `.git` and `.zas` remain excluded.
## Page metadata
Put YAML in the leading HTML comment of a Markdown or HTML page:
```markdown
# My article
```
For resolved settings such as `language`, page metadata takes precedence over the nearest directory `.zas.yml`, which takes precedence over site settings. Page metadata remains available through `.Page`.
| Page setting | Effect |
| --- | --- |
| `title` | Override the first H1 as the page title. |
| `language` | Override the resolved language. |
| `date` | Explicit RFC3339 publication timestamp with a timezone. |
| `updated` | Explicit RFC3339 update timestamp with a timezone. |
| `summary` | Plain-text summary string. |
| `tags` | List of strings. |
| `publish: false` | Exclude a standalone page, while retaining it as embed content. |
| `template: false` | Skip the page's own Go template execution. |
| `draft: true` | Exclude the page from feeds and Markdown twins; existing HTML generation remains enabled. |
| `publish_markdown: false` | Opt this page out of Markdown twins. |
| `feed: false` | Opt this page out of feeds. |
| `article: false` | Classify a utility page as outside the article feed selection. |
`template: false` still allows parsing and embed processing. Use `-no-plugins` to prevent content-triggered external programs; see the [trust model](templates.md).
## Languages
Set the site default in `site.language`. For a language subtree, add a `.zas.yml` such as:
```yaml
language: es
```
Place it in `es/`, alongside `es/index.md` and other Spanish pages. Pages can also override their language individually.
Translations live in `.zas/i18n.yml`:
```yaml
Hello:
en: Hello
es: Hola
ca: Hola
```
Use `{{.E "Hello"}}` in a page or layout. Missing translations produce `**Hello**`. Language directories with matching relative page paths are paired automatically for sitemap `hreflang`; a page-only language override does not create that pairing.
---
Source: https://dario.cat/zas/templates.md
# Templates and plugins
Zas uses Go templates in page content and in the shared `.zas/layout.html`, with different escaping behavior.
## Layout
A minimal layout can use:
```html
{{.Title}}
{{with .Summary}}{{end}}
{{.Body}}
```
The layout runs through Go's `html/template`, which escapes values according to their HTML context. `.Body` contains the already-rendered page body.
## Metadata helpers
| Helper | Value |
| --- | --- |
| `.Title` | Explicit page `title`, otherwise the first H1. |
| `.Language` | Resolved page language. |
| `.Canonical` | Absolute page URL with a final `/index.html` replaced by `/`. |
| `.URL` | Absolute generated path; retains `/index.html` when that is the filename. |
| `.Date` | Explicit RFC3339 `date`, or zero time. |
| `.Updated` | Explicit `updated`, otherwise the tracked source's latest git commit date, or zero time. |
| `.Summary` | Explicit `summary`, or an empty string. |
| `.Tags` | Explicit string-list `tags`, in their original order. |
| `.Page` | Page YAML map. |
| `.Directory` | Directory configuration map. |
| `.Resolve "language"` | Page, directory, then site setting. |
| `.Extra "/site/baseurl"` | Direct string lookup in the site configuration. |
A standalone `article.md` has canonical `/article.html`; the helper only normalizes index pages. To format a publication date, first check that it is present:
```html
{{if not .Date.IsZero}}{{end}}
```
Invalid explicit metadata stops template execution when its helper is used. Publication dates are never inferred from git, file timestamps or build time. A full-history checkout gives `.Updated` accurate git history.
Inside a page's own content, `.Page`, `.Title` and `.FirstTitle` use a best-effort preview. The layout sees the final values after page rendering. `.Body` is empty inside the page's own template.
## Page listings
Set `site.page_listings: true` to expose `.Pages "posts"` in page, Markdown
and layout templates. The option defaults to false; disabled sites do no
listing scan, and a `.Pages` call explains how to enable it.
For a page archive, use explicit HTML escaping because page content runs
through `text/template`:
```html
```
In the layout, use `.URL`, `.Title` and `.Summary` directly: `html/template`
auto-escapes their plain strings. `.Pages(section)` returns independent
`[]PageSummary` slices and an error. Summaries contain:
| Field | Value |
| --- | --- |
| `Title` | Literal page `title`, otherwise static first H1 text. |
| `URL` | Escaped root-relative canonical path, including any baseurl hosting subpath, for local preview navigation. |
| `Canonical` | The existing canonical helper's path with `site.baseurl`, or root-relative if unset. |
| `Date` | Explicit RFC3339 publication date as `time.Time`, otherwise zero time. |
| `Language` | Page, nearest directory configuration, then site language. |
| `Summary` | Literal page `summary`, otherwise empty. |
`posts` recursively includes the directory's pages and nested article
indexes, omitting only `posts/index.md` or `posts/index.html`. It does not
match `posts-old`. Empty and `.` sections select the root; missing sections
return empty lists. Paths must be relative directory paths; trailing `/`
is allowed. Traversal, absolute paths, backslashes, queries, fragments and
encoded path syntax are invalid and reported when `.Pages` is called.
As with other template failures, a full build may already have cleared
deploy; use a staging directory to preserve published output on failure.
Known dates sort newest first, then by URL; undated pages sort last by URL.
Dates never come from file timestamps, git or build time.
Listings use a complete static-source snapshot collected before rendering,
without executing templates, embeds or plugins. They skip the layout,
deploy output, symlinks, hidden sources (following the normal dot-directory
allowlist), `publish: false` and `draft: true`. Drafts keep their existing
standalone HTML behavior. Listing metadata must be valid literal values in
the leading YAML comment; template actions there are rejected unless
`template: false`. Template-generated H1 text yields an empty title; provide
a literal `title` to name it. A leading action that could generate the
configuration comment is rejected: put a literal comment or heading first.
Missing static titles are allowed. Invalid static metadata fails before
full-build cleanup; generated publication flags that disagree with the
snapshot fail the build when rendering reveals them. Enabled runs render
every HTML/Markdown source so all archives reflect additions, removals,
renames and metadata edits; newly unpublished
HTML is removed during incremental builds. This trades incremental render
speed for consistent lists.
## JSON in layouts
`dict`, `list` and `json` are layout-only helpers. Build objects rather than passing a pre-encoded JSON string:
```html
{{$person := dict "@type" "Person" "name" "Dario Castañé" "url" .Site.BaseURL}}
```
`json` serializes the value with `encoding/json` and retains its HTML-sensitive character escaping. Serialization errors fail the build. It adds no schema automatically.
## Embeds
Built-in handlers support Markdown, HTML and plain text:
```html
```
Page-body embeds resolve relative to the containing page. Layout embeds resolve relative to the site root. Built-in nested embeds remain inside the site root and have a depth limit.
Mark an embedded-only navigation file `publish: false` to prevent it also becoming a standalone page. With Markdown twins enabled, Markdown embeds must occupy a standalone line; combinations with reference definitions or footnotes are rejected to avoid changing reference scopes.
## Plugin and template trust model
Page content runs through Go's `text/template` with no automatic escaping. This includes template actions inside code fences. To display literal actions, put `template: false` in the page's leading configuration comment. The layout still runs normally.
External subcommands named `zs` and MIME handlers named `mzs` are programs found on `PATH`. Content can trigger MIME handlers through embeds, or `zs` programs through `