Writing blog posts
Blog posts are Markdown files in src/content/blog/. The theme uses Astro Content Collections, so each post gets a typed schema, a stable slug, and a generated route — for free.
Anatomy of a post
Section titled “Anatomy of a post”Create src/content/blog/getting-started-with-aurora.md:
---title: "Getting Started with Aurora"description: "A 5-minute walk through Aurora's core concepts."date: 2026-01-15author: "Alex Rivera"category: "Tutorial"image: "/blog/getting-started.jpg"draft: false---
Welcome to Aurora. This post walks through everything you need to know to shipyour first project this afternoon.
## The first 30 seconds
Aurora ships with sensible defaults — you can start using it immediately…
## More headings
Markdown headings (`##`, `###`) become anchored section dividers. The themeauto-generates a table of contents from them.

> Quotes get a tasteful tinted treatment.
`code` inline. Or a fenced block:
\`\`\`tsconst aurora = createAurora({ theme: "light" });\`\`\`That’s all. Save it and /blog/getting-started-with-aurora/ renders immediately — the slug is derived from the filename.
What lands where
Section titled “What lands where”| Frontmatter field | Where it shows |
|---|---|
title | Post <h1>, blog index card title, <title> tag, OG title. |
description | Card subtitle, meta description, OG description. |
date | Card date, <time> element on the post. ISO format. |
author | Byline. |
category | Card tag, category filter on the blog index. |
image | Card hero image, OG image for that post. |
draft | If true, the post is excluded from the build entirely. |
The schema lives in src/content.config.ts (or src/content/config.ts in older themes). Add a field there if you want the schema to accept it.
Drafts
Section titled “Drafts”Set draft: true in the frontmatter to keep a post out of production:
---title: "Half-written thoughts on observability"draft: truedate: 2026-02-01---In dev (npm run dev), drafts are visible at their URL but hidden from the blog index. In npm run build, they’re excluded entirely.
Categories and filtering
Section titled “Categories and filtering”category is a free-text string. The blog index (src/pages/blog/index.astro) reads every post’s category and renders a filter row at the top. To rename a category globally, edit the field in every post — categories aren’t centralized.
For tighter control, swap the schema to use a string union in src/content.config.ts:
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(), draft: z.boolean().default(false), }),});Now Astro errors at build time if a post uses an unknown category — instant typo protection.
Custom slugs
Section titled “Custom slugs”By default the slug is the filename minus .md. Override by adding to the frontmatter:
---slug: "v2-launch"title: "Aurora 2.0 — what's new"---Becomes /blog/v2-launch/ regardless of filename.
MDX (optional)
Section titled “MDX (optional)”If you want to embed components inside posts (callouts, custom charts, an embedded video player), use .mdx instead of .md:
---title: "Launch announcement"date: 2026-03-01author: "Sarah Kim"category: "Product"---
import VideoEmbed from "~/components/VideoEmbed.astro";
We just launched.
<VideoEmbed videoId="dQw4w9WgXcQ" />
The rest of the article continues in plain Markdown…MDX requires @astrojs/mdx — npm install @astrojs/mdx and add it to astro.config.mjs:
import mdx from "@astrojs/mdx";export default defineConfig({ integrations: [mdx(), /* … */],});Where the posts render
Section titled “Where the posts render”src/pages/blog/index.astro— the listing page. IteratesgetCollection("blog"), filters out drafts in production, sorts by date.src/pages/blog/[slug].astro— the post template. Reads frontmatter, renders the Markdown body, wires up “next/previous post” navigation.
If you want to change the post layout (more whitespace, different sidebar, related-posts grid), edit [slug].astro directly.
What’s next
Section titled “What’s next”- Frontmatter reference — the full schema and what each field accepts.
- Images & media — where to put hero images, optimization, and alt text.