patternjavascriptastroModerate
Astro content collections for typed, validated content
Viewed 0 times
Astro 2.0+ (content collections stable)
content collectionsastro:contentzod schemafrontmattergetCollectiontype-safe content
Error Messages
Problem
Managing blog posts, docs, or other Markdown content with no type safety — frontmatter fields are unvalidated, typos in slugs go undetected, and querying is done with raw glob imports.
Solution
Define content collections with Zod schemas in src/content/config.ts:
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content', // markdown/mdx
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
cover: z.object({
src: z.string(),
alt: z.string()
}).optional()
})
});
const authors = defineCollection({
type: 'data', // JSON/YAML only
schema: z.object({
name: z.string(),
bio: z.string()
})
});
export const collections = { blog, authors };
// In a page:
import { getCollection, getEntry } from 'astro:content';
const posts = await getCollection('blog', ({ data }) => !data.draft);
const author = await getEntry('authors', 'alice');
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content', // markdown/mdx
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
cover: z.object({
src: z.string(),
alt: z.string()
}).optional()
})
});
const authors = defineCollection({
type: 'data', // JSON/YAML only
schema: z.object({
name: z.string(),
bio: z.string()
})
});
export const collections = { blog, authors };
// In a page:
import { getCollection, getEntry } from 'astro:content';
const posts = await getCollection('blog', ({ data }) => !data.draft);
const author = await getEntry('authors', 'alice');
Why
Content collections give Markdown files a typed schema enforced at build time. Zod validates frontmatter — missing fields and wrong types throw build errors rather than silent runtime bugs. getCollection() returns fully typed entries with IntelliSense.
Gotchas
- Content must be in src/content/ — not src/pages/ or public/
- z.date() parses ISO date strings from frontmatter — use quotes in YAML: pubDate: '2024-01-01'
- getCollection() is async — it cannot be used outside of Astro frontmatter or server endpoints
- Images in frontmatter can use z.image() to get width/height metadata automatically
Code Snippets
Fetching and sorting blog posts from a collection
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog', ({ data }) => !data.draft);
const sorted = posts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---
{sorted.map(post => (
<article>
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
</article>
))}Context
When managing structured content like blog posts or documentation in Astro
Revisions (0)
No revisions yet.