Astro Content Collections: the blog setup I wish I had earlier
1 min read
0 views
astro typescript
Every static blog setup I built before Astro had the same failure mode: a typo in frontmatter that silently broke the page. A missing date, a tags string instead of an array, and the build would happily ship broken HTML.
Content Collections fix this with a schema.
Define the contract once
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
date: z.coerce.date(),
tags: z.array(z.string()).default([]),
}),
});
export const collections = { blog };
Now astro build fails with a precise error if any markdown file violates the schema. The date is a real Date object, not a string you have to parse in every template.
Querying is trivial
const posts = (await getCollection('blog')).sort(
(a, b) => b.data.date.valueOf() - a.data.date.valueOf()
);
Fully typed. Your editor autocompletes post.data.title and yells at you for post.data.titel.
The part people miss
Reading time, tag pages, RSS feeds: all of it derives from the collection at build time. No client-side JavaScript, no runtime cost. The browser receives plain HTML, which is exactly what a blog should be.