The content system is built on Astro’s content collections API. All content lives in src/content/ and is validated against Zod schemas defined in src/content.config.ts.
Who this is for
- Implementors working with frontmatter schemas, content routing, or collection configuration
- Developers adding new collections or modifying schema definitions
- Editors understanding how content files map to published pages
Schema Locations
All content collections use Zod-validated frontmatter schemas. The authoritative field inventory is always the schema source file — this doc teaches the system model, not an exhaustive field list.
| Collection | Schema location | Ownership |
|---|---|---|
| pages, articles | src/content.config.ts (contentSchema) | SITE-OWNED |
| theme-docs | defineDocsCollection() in src/core/config/theme-docs-collection.ts | CORE-OWNED |
| site-docs | defineDocsCollection() in src/site/config/site-docs.ts | SITE-OWNED |
| fragments | src/content.config.ts (inline) | SITE-OWNED |
Both docs collections use the shared defineDocsCollection() factory from src/core/config/docs-collection-factory.ts (CORE-OWNED). The factory produces a validated Astro collection from parameters — each collection customizes topics, docId prefix, and extensions.
Collections Overview
| Collection | Purpose | Routed? |
|---|---|---|
pages | Utility and simple content pages (about, contact, legal) | Yes |
articles | Blog posts, news, case studies | Yes |
docs | Internal documentation for implementors, developers, and AI agents | Yes |
fragments | Reusable content blocks composed into other pages | No |
Pages and Articles
Pages and articles share the same schema. The distinction is in URL routing and default behavior, not field structure.
Representative frontmatter
---
title: About Us
description: Learn more about our team and mission.
slug: /about
draft: false
category: company
tags:
- team
- mission
heroTitle: Meet the Team Behind the Work
---
Key fields
title(required) — page title, used as<h1>and in listingsdescription(required) — short summary for meta tags and listing cardsslug(optional) — overrides the default URL path derived from the file path and namedraft(default:false) — whentrue, excluded from builds, sitemap, and indexingnoindex(default:false) — suppresses search engine indexing for the pagedatePublished/dateModified(optional, ISO 8601) — resolves in order: frontmatter value → git commit date → file datecategory(optional) — primary category for taxonomytags(optional) — array of tag stringsheroTitle(optional) — marketing-oriented title override for hero sectionsshortTitle(optional) — compact label for navigation and breadcrumbstoc(default:true) — enables table of contents generationreadingTime(default:true) — enables estimated reading time displaylightbox(optional, boolean) — enables or disables the image lightbox for a specific page; when omitted, the collection default fromsrc/site/config/platform.config.tsapplies (REQ-00049)
Taxonomy
Categories
Categories use an explicit mapping table defined in site config (siteConfig.taxonomy.categories). Each entry maps a display name to a URL slug:
// src/site/config.ts
taxonomy: {
categories: {
"Company News": "company-news",
"Case Studies": "case-studies",
"Engineering": "engineering",
},
}
The frontmatter category value is matched case-insensitively against the display names in this table. Values that do not match any registered category generate a build-time warning. Category pages are indexable by default (siteConfig.taxonomy.categoryIndexable).
Tags
Tags are emergent — no registration is required. Any string in the tags array becomes a valid tag. Different casings (TypeScript, typescript, TYPESCRIPT) resolve to the same tag via slug normalization at build time.
Tag pages are noindex by default (siteConfig.taxonomy.tagIndexable).
Generated taxonomy pages
| URL pattern | Description |
|---|---|
/articles/categories/ | Index of all categories |
/articles/categories/{slug}/ | Articles in a specific category |
/articles/categories/{slug}/page/{n}/ | Paginated category listing |
/articles/tags/ | Index of all tags |
/articles/tags/{slug}/ | Articles with a specific tag |
/articles/tags/{slug}/page/{n}/ | Paginated tag listing |
Heading authoring baseline
- The page
<h1>comes from frontmatter (title, orheroTitlewhere supported). - In markdown/MDX body content, start at
##and below. - Do not author prose
#headings in routed collections (pages,articles,docs). #remains valid inside fenced code blocks for examples/comments.
For the complete field inventory and validation rules, see src/content.config.ts.
Docs
The docs collection has additional fields for documentation-specific metadata. The full frontmatter contract is documented in the Documentation Guide (DOC-00001).
Representative frontmatter
---
title: Design Tokens
description: Reference for the three-layer design token architecture.
docId: DOC-00004
topic: design-system
audience:
- implementor
- developer
docType: reference
order: 4
datePublished: 2026-02-27
draft: false
relatedDocs:
- DOC-00002
---
Key differences from pages/articles
docId(required) — immutable identifier inDOC-NNNNNformat; used for cross-referencestopic— groups related docs for sidebar navigationaudience— who the doc is written for (implementor,developer,editor)docType— document classification (guide,reference,policy,how-to,tutorial)noindexdefaults totrue— docs are internal reference, not marketing contentshowRequirements(default:true) — renders a requirements section if any requirement references thisdocIdrelatedDocs— enables a related documents section when populated
Docs default overrides
| Field | Docs Default | Shared Default | Reason |
|---|---|---|---|
| noindex | true (theme-docs) / false (site-docs) | false | Theme-docs are internal; site-docs are customer-facing |
| tocStartLevel | 2 | 1 | Docs start TOC at H2 |
| tocEndLevel | 3 | 2 | Docs end TOC at H3 |
For the complete field inventory, see src/content.config.ts. For the full docs frontmatter contract and writing standards, see the Documentation Guide (DOC-00001).
Fragments
Fragments are not routed — they have no URL and are never rendered as standalone pages. They are reusable content blocks consumed programmatically by other pages. The collection uses a two-directory loader that merges entries from src/core/content/fragments/ (core layer) and src/content/fragments/ (site layer).
Representative frontmatter
---
title: Company Mission Statement
notes: Used on the about page and footer.
fragmentId: mission-statement
---
fragmentId(required) — stable reference key used by consuming pagestitle(optional) — internal editorial label, not rendered as a headingnotes(optional) — editorial context for content authors
URL Routing
| Collection | URL pattern | Example |
|---|---|---|
pages | /{slug}/ | /about/, /contact/ |
articles | /articles/{file-slug}/ | /articles/case-study-acme/ |
docs | /theme-docs/{file-slug}/ | /theme-docs/design-tokens/ |
fragments | (not routed) | — |
- Trailing slash is enforced on all routes
- All routed collections support an optional
slugfield that overrides the default path-derived URL - Canonical URLs are auto-generated from
siteUrl + route; thecanonicalfield overrides when set
Draft Content
When draft: true on any collection entry:
- Excluded from production build output
- Excluded from sitemap
- Marked
noindex, nofollowfor robots - Visible on the dev server for preview
Noindex Defaults
| Collection | Default | Rationale |
|---|---|---|
pages | Indexed | Marketing/utility pages should be discoverable |
articles | Indexed | Blog/news content should be discoverable |
docs | Not indexed | Internal reference documentation |
Media and Images
Image Optimization (REQ-00076)
All images used in content must go through Astro’s built-in image optimization pipeline. Use the <Image> component from astro:assets rather than raw <img> tags.
---
import { Image } from "astro:assets";
import heroImage from "@/assets/images/hero.jpg";
---
<Image src={heroImage} alt="Descriptive alt text" width={1200} height={630} />
Astro automatically generates optimized WebP/AVIF variants, adds width and height to prevent layout shift, and applies lazy loading by default.
For images referenced in content frontmatter, define the field as an image reference type in the collection schema so Astro can process it at build time.
Art Direction (REQ-00077)
When different crops or aspect ratios are needed across breakpoints, use the <Picture> component or a native <picture> element with <source media="..."> elements:
---
import { Picture } from "astro:assets";
import heroDesktop from "@/assets/images/hero-desktop.jpg";
---
<Picture
src={heroDesktop}
alt="Descriptive alt text"
formats={["avif", "webp"]}
/>
For true art direction (different source images per viewport), use a native <picture> element pointing to separately optimized assets for each breakpoint.
Figures and Captions (REQ-00079)
Figures with captions must use semantic <figure> and <figcaption> markup:
<figure>
<Image src={image} alt="Chart showing quarterly growth" />
<figcaption>Q3 2025 revenue by region. Source: Finance team.</figcaption>
</figure>
Rules:
<figure>wraps the image and its caption as a unit.<figcaption>is the only text child alongside the image — do not nest headings inside figures.- Alt text and figcaption are complementary: alt describes the image content; figcaption provides context, attribution, or explanation.
- Decorative images (no informational content) use
alt=""and may omit the figure wrapper.