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.