Frontmatter reference: every field this theme understands
A complete reference for the post and page frontmatter schema — required and optional fields, defaults, validation rules, and what each one actually does.
This theme uses Astro Content Collections with a strict
Zod schema. Every post and page is type-checked at
build time, so a missing required field or a typo in pubDate fails
loudly instead of silently breaking the site.
The full schema lives in src/content.config.ts. Here is what each field does, when you need it, and what it defaults to.
| Field | Type | Notes |
|---|---|---|
title | string | 1–140 characters. Used as <title>, OG title, H1. |
description | string | 1–280 characters. Used as meta description, OG, RSS. |
pubDate | date | Coerced from any ISO-parseable string. |
For pages (src/content/pages/**), pubDate is optional — pages
are not paginated or archived.
updatedDate: 2026-05-12Set this whenever you make a meaningful edit. It controls the “Updated”
line in the post header, the RSS <updated> tag, the OG
article:modified_time meta and the sitemap entry.
tags: [typescript, astro, accessibility]categories: [Tutorials]Both default to []. Tags drive the /tags/... index. Categories drive
/categories/.... Both appear on the right-hand panel when ranked
high enough in the “Trending tags” widget. There is no enforced
case-style — pick a convention and stick to it.
draft: trueDefault false. When true, the post is included in dev mode (so you
can see it while writing) but excluded from production builds, the
sitemap and the RSS feed.
unlisted: trueDefault false. When true, the post is built and deployed (its
URL works) but hidden from every listing surface: home page, archives,
tags, categories, RSS, and sitemap. Use this to share a post by direct
link without surfacing it in navigation.
unlistedHideFromSeo: falseControls the <meta name="robots" content="noindex, nofollow"> tag
independently. Defaults to true when unlisted: true. Set to false
to keep an unlisted post indexable by search engines, or set to true
on a listed post to hide it from search engines without removing it from
listings.
See the Unlisted posts guide for the full picture and a live demo.
heroImage: ../../../assets/images/posts/featured-images-and-media/coastline.jpgheroImageAlt: 'A long exposure of waves crashing on a rocky coastline'Three shapes are accepted:
- A path relative to the markdown file pointing into
src/assets/images/posts/<post-identifier>/— resolved through Astro’simage()helper, fully optimized (WebP + responsivesrcset). Recommended. - A
/public/...absolute path — served as-is, no optimization. - An external
https://...URL — optimized at build if the host is allow-listed inimage.remotePatterns(seeastro.config.mjs).
The image is used both as the card thumbnail on listings and as the
hero on the post page. heroImageAlt becomes the alt attribute —
please always set it.
The companion post Featured images & media goes deeper into image authoring.
showFeaturedImage: falseA per-post override of SITE.showFeaturedImages from
src/config.ts. Set false to suppress the hero on a
single post even though the site default is “show”.
For listing-card sizing behavior (fixed vs dynamic height), use
SITE.dynamicPostCardHeight in src/config.ts for the
site default, or set dynamicPostCardHeight in frontmatter to override
it per post.
dynamicPostCardHeight: trueOptional per-post override of SITE.dynamicPostCardHeight. This only
affects how the post’s card behaves on horizontal listing views:
true: this post’s listing card can grow (dynamic height).false: this post’s listing card keeps fixed Chirpy-style height.- omitted: falls back to the site-level
SITE.dynamicPostCardHeight.
canonicalURL: https://example.com/canonical/path/Optional override for the <link rel="canonical"> tag. Useful when
republishing a post that already lives elsewhere.
comments: falsePer-post toggle for Giscus. If omitted, comments follow the site-wide
GISCUS.enabled setting. Set explicitly to false to silence comments
on a single post (e.g. on this very reference page).
toc: falseDefaults to true. The right-hand sticky table of contents is built
from your H2–H4 headings with scroll-spy. Some posts (a photo essay,
a short announcement) read better without one — set toc: false.
pinned: truePinned posts always sort to the top of listings and the home page, above newer posts. Use sparingly.
math: trueOpt the post into KaTeX rendering. The stylesheet (katex.min.css,
~29 kB) is only loaded on pages that set this flag. See the
LaTeX math post for full syntax.
lang: enLocale override. The theme normally infers locale from the file
path (posts/en/... → en, posts/fr/... → fr), so you should
rarely need this.
translationKey: welcomeThe bridge between EN and FR variants of the same article. Two posts
that share a translationKey are considered translations of each
other; the language switcher uses this to land you on the equivalent
article instead of bouncing to the locale home page. If omitted, the
theme falls back to the file slug. The
i18n post shows the full picture.
Pages (src/content/pages/**) accept everything posts do (with
pubDate made optional) plus:
showInNav: trueThis is reserved for future use; navigation is currently driven by the
NAV array in src/config.ts.
---title: A complete exampledescription: Demonstrates every field in one place.pubDate: 2026-05-01updatedDate: 2026-05-03tags: [example, reference]categories: [Reference]draft: falseunlisted: falseheroImage: ../../../assets/images/posts/featured-images-and-media/coastline.jpgheroImageAlt: A long exposure of a rocky coastlineshowFeaturedImage: truecanonicalURL: https://example.com/example/comments: truetoc: truepinned: falsemath: falsetranslationKey: example---| Error | What it means |
|---|---|
pubDate: Required | You forgot pubDate (or misspelled it). |
description: Too long (max 280) | Your description exceeds 280 characters. |
heroImage: Invalid URL | (Only fires for external URLs that fail Zod’s URL parse.) |
Cannot find module '...' | An MDX import path is wrong — check the relative path to src/components/. |
Comments are intentionally turned off for this post via
comments: false — it is a reference, not a discussion.