Content & routing #
Glaze turns a folder of .dj files into a folder of HTML pages. Understanding how files
map to URLs — and what you can put in them — is the core of working with Glaze.
How routing works #
Every .dj file inside content/ becomes a page. The URL is derived directly from the
file path, with one rule: nested index.dj files collapse to the parent directory URL.
All generated paths end with a trailing slash.
| File | URL |
|---|---|
content/index.dj |
/ |
content/about.dj |
/about/ |
content/blog/index.dj |
/blog/ |
content/blog/_index.dj |
/blog/ (unlisted) |
content/blog/my-post.dj |
/blog/my-post/ |
content/blog/2026/hello.dj |
/blog/2026/hello/ |
Underscore-prefixed index files #
Files named _index.dj behave like index.dj (they resolve to the parent directory URL)
but are automatically marked as unlisted. Unlisted pages are rendered and accessible
by URL, but excluded from page collections by default. This makes them ideal as section
overview pages that should not appear alongside regular content in listings.
content/
blog/
_index.dj <- renders at /blog/, excluded from collections
first-post.dj <- renders at /blog/first-post/, included in collections
second-post.dj <- renders at /blog/second-post/, included in collections
See Frontmatter for the unlisted field and Page Collections for
collection filtering details.
Overriding the URL #
Use the slug frontmatter field to set a custom URL path for a page.
A relative slug (no leading /) is resolved relative to the file’s directory.
A file at blog/my-post.dj with slug: custom-title produces /blog/custom-title/:
---
title: About me
slug: about-the-author
---
An absolute slug (leading /) ignores the directory context entirely:
---
slug: /about-the-author
---
Use an absolute slug when you want a page to appear at a URL unrelated to where the file
lives, or to place index.dj at /:
---
slug: /
---
Slug values are lowercased and slugified automatically. Full details: Frontmatter § slug.
Writing a page #
A page is a .dj file with optional NEON frontmatter at the top, separated from the
content by --- (or +++) fences:
---
title: Hello world
date: 2026-02-24T10:00:00+01:00
draft: false
tags:
- hello
- news
---
# Hello world
Welcome to my first post. Content goes here.
Frontmatter is parsed as NEON. Everything after the closing fence is Djot content.
Pages without frontmatter are valid. Glaze infers the title from the filename
(e.g. my-post becomes My Post) when title is not set.
Frontmatter fields #
Reserved fields Glaze acts on:
| Field | Type | Description |
|---|---|---|
title |
string | Human-readable page title |
slug |
string | Override the auto-generated URL path |
date |
datetime | Publish date; exposed as a Chronos instance in templates |
weight |
int | Sort order in collections (lower values sort first) |
draft |
bool | Excluded from glaze build unless --drafts is passed |
unlisted |
bool | Rendered but excluded from collections; auto-set for _index.dj files |
type |
string | Explicit content type override |
template |
string | Per-page template override (without .sugar.php) |
description |
string | Default meta description |
outputPath |
string | Override the generated output file path (e.g. 404.html) |
| taxonomy keys | list | tags, categories, etc. — configured in glaze.neon |
Any other key is preserved as custom metadata. Nested maps and lists are supported and accessible in templates via dotted path:
---
hero:
title: Build fast static sites
primaryAction:
label: Read docs
href: /installation
---
<?= $page->meta('hero.title') ?>
<?= $page->meta('hero.primaryAction.href') ?>
Full field reference: Frontmatter.
Output path override #
By default, Glaze writes every page as {slug}/index.html and serves it at /{slug}/.
The outputPath frontmatter field lets you bypass this convention and control the exact
file path that is written during glaze build.
When outputPath is set, the page URL is derived directly from the value instead of
following the /{slug}/ directory-index convention.
---
title: Page Not Found
outputPath: 404.html
unlisted: true
---
# Not Found
The page you are looking for does not exist.
This page will be written to public/404.html and served at /404.html. Glaze’s dev
server automatically picks it up as a custom 404 page: any request that does not match a
known route will return this page with a 404 status code.
See Frontmatter § outputPath for the full reference and more use cases.
Content types #
Content types classify pages by path prefix and let you apply shared frontmatter
defaults automatically. You define them in glaze.neon:
contentTypes:
blog:
paths:
- match: blog
createPattern: blog/{date:Y/m}
defaults:
template: blog
draft: false
Every page whose path starts with blog/ automatically gets template: blog and
draft: false without you having to set them per-page. The createPattern controls
where glaze new --type blog places new files.
A page can also declare its type explicitly in frontmatter to bypass path matching:
---
type: blog
title: A post that lives outside the blog folder
---
See Configuration for the full contentTypes reference.
Static files #
Files in static/ are copied verbatim to public/ during glaze build, preserving
their paths:
-
static/robots.txt→ served at/robots.txt -
static/favicon.ico→ served at/favicon.ico -
static/styles/app.css→ served at/styles/app.css
Glaze’s dev server also serves static/ files directly at their matching paths.
Non-Djot files inside content/ (images, PDFs, downloads, etc.) are treated the same
way — copied to public/ at their matching paths during build and served as-is during
development. This means you can colocate images with content:
content/
blog/
my-post.dj
my-post-cover.jpg <- served at /blog/my-post-cover.jpg
What the Sugar template sees #
Once Glaze renders a page, these variables are available in every Sugar template:
| Variable | Type | Description |
|---|---|---|
$title |
string |
Page title |
$content |
string |
Rendered Djot HTML |
$url |
string |
Current URL path |
$meta |
array |
Merged page metadata |
$page |
ContentPage 🔷 |
Full page object |
$site |
SiteConfig 🔷 |
Global site config |
$this |
SiteContext 🔷 |
Collections, pagination, taxonomy helpers |
See Templating for the full variable and directive reference.
Multilingual sites #
Glaze has built-in support for multilingual sites. Each language gets its own
content directory and URL prefix. String translations, language switching helpers,
and automatic sitemap hreflang entries are all included.
See Internationalization for the full setup guide.