Content Collections
How journal posts and other Markdown content are defined, validated and queried.
Updated: September 2026·License: Commercial & Personal
Defining a collection
Collections give your Markdown a schema, so a missing or misspelled frontmatter field fails the build instead of the page:
ts
// src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const journal = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/journal' }),
schema: z.object({
title: z.string(),
description: z.string(),
publishDate: z.coerce.date(),
draft: z.boolean().default(false),
}),
});
export const collections = { journal };Writing an entry
markdown
---
title: "Notes from the four o'clock shift"
description: "Working notes on topology and look development."
publishDate: 2026-02-14
---
Body copy starts here.Querying entries
astro
---
import { getCollection } from 'astro:content';
const posts = (await getCollection('journal', ({ data }) => !data.draft))
.sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf());
---
<ul>
{posts.map((post) => (
<li>
<a href={`/journal/${post.id}/`}>{post.data.title}</a>
</li>
))}
</ul>The filter callback runs at build time, so drafts never reach the output at all.
Explore production-ready themes
Hand-built Astro themes — SaaS, storefront, portfolio, and dashboard.