Content Collections, Explained
A practical tour of Astro content collections: typed frontmatter, the glob loader, and rendering Markdown and MDX.
Astro content collections turn a folder of Markdown into a typed, queryable data source. Kepler’s blog is built entirely on top of them. Here is the shape of it.
Define the collection
A collection pairs a loader (where the files live) with a schema (what their frontmatter must contain):
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
schema: z.object({
title: z.string(),
pubDate: z.coerce.date(),
tags: z.array(z.string()).default([]),
}),
});
export const collections = { blog };
Because the schema is Zod, a typo in your frontmatter fails the build instead of shipping a broken page.
Query and render
Fetch entries with getCollection, then render one with render:
---
import { getCollection, render } from 'astro:content';
const posts = await getCollection('blog');
const { Content } = await render(posts[0]);
---
<Content />
Why MDX?
This very post is an .mdx file. MDX lets you drop components into prose when a
plain paragraph will not do — callouts, charts, interactive demos. For everyday
writing, plain Markdown is lighter and just as well supported. Use whichever fits
the page.