Frontmatter reference
The blog collection’s schema is defined in src/content.config.ts (or src/content/config.ts in older themes). This page mirrors that schema and explains each field.
Default schema
Section titled “Default schema”const blog = defineCollection({ type: 'content', schema: z.object({ title: z.string(), description: z.string(), date: z.date(), author: z.string(), category: z.string(), image: z.string().optional(), draft: z.boolean().default(false), }),});Field reference
Section titled “Field reference”title (required)
Section titled “title (required)”title: "Getting Started with Aurora"- Type: string
- Required: yes
- Used as: post
<h1>, blog index card title,<title>tag, OG / Twitter share title.
Keep under ~60 characters for clean display in search results.
description (required)
Section titled “description (required)”description: "A 5-minute walk through Aurora's core concepts."- Type: string
- Required: yes
- Used as: card subtitle on the blog index,
<meta name="description">, OG / Twitter share description.
~150 characters is the sweet spot. Beyond that, Google truncates with an ellipsis.
date (required)
Section titled “date (required)”date: 2026-01-15# or with time:date: 2026-01-15T14:30:00.000Z- Type: YAML date (parsed as JS
Date) - Required: yes
- Used as: card date, post byline date,
<time datetime="...">for SEO, sort order on the blog index.
ISO format is safest. Astro’s content layer parses both YYYY-MM-DD and full ISO strings; bare strings like "Jan 15, 2026" will fail the schema.
author (required)
Section titled “author (required)”author: "Alex Rivera"- Type: string
- Required: yes
- Used as: byline on the post and the card.
For multi-author posts, comma-separate ("Alex Rivera, Sarah Kim") or convert to an array — see Extending the schema.
category (required)
Section titled “category (required)”category: "Engineering"- Type: string
- Required: yes
- Used as: the tag chip on cards, the filter facet on the blog index.
To enforce a fixed set, use a z.enum() — see Extending the schema.
image (optional)
Section titled “image (optional)”image: "/blog/getting-started.jpg"- Type: string path (relative to
public/) - Required: no
- Used as: hero image on the post, card thumbnail, OG image for that specific post.
Recommended size: 1200×630 PNG or JPG so it doubles as the OG share card. If omitted, the card uses a placeholder color and the OG image falls back to siteConfig.seo.ogImage.
draft (optional)
Section titled “draft (optional)”draft: true- Type: boolean
- Default:
false - Used as: build filter.
true— visible in dev (npm run dev), excluded fromnpm run build.false— published.
Optional fields you can add
Section titled “Optional fields you can add”The fields below aren’t in the default schema, but they’re commonly useful. Add them by extending src/content.config.ts.
For multi-label posts (different from a single category):
tags: z.array(z.string()).optional(),tags: ["typescript", "performance", "deploy"]featured
Section titled “featured”For pinning to the top of the blog index:
featured: z.boolean().default(false),featured: trueThen in src/pages/blog/index.astro, sort featured posts first:
const posts = (await getCollection("blog")) .sort((a, b) => Number(b.data.featured ?? 0) - Number(a.data.featured ?? 0) || b.data.date.getTime() - a.data.date.getTime());updated
Section titled “updated”For posts you revise:
updated: z.date().optional(),date: 2026-01-15updated: 2026-03-08excerpt
Section titled “excerpt”For a longer card description that differs from the SEO meta:
excerpt: z.string().optional(),excerpt: "We rebuilt Aurora's onboarding from scratch. Here's what we learned about UX research, prototyping, and shipping with confidence."Extending the schema
Section titled “Extending the schema”Open src/content.config.ts and add fields to the Zod schema:
import { defineCollection, z } from "astro:content";
const blog = defineCollection({ type: "content", schema: z.object({ title: z.string(), description: z.string(), date: z.date(), author: z.string(), category: z.enum(["Tutorial", "Engineering", "Design", "Product"]), image: z.string().optional(), tags: z.array(z.string()).default([]), featured: z.boolean().default(false), updated: z.date().optional(), draft: z.boolean().default(false), }),});Type-safe everywhere — Astro errors at build time if a post is missing a required field or uses an invalid value.
Common gotchas
Section titled “Common gotchas”What’s next
Section titled “What’s next”- Writing blog posts — the workflow for writing and publishing.
- Images & media — where to put
imagefiles and how to optimize them.