Alle Beiträge
astro typescript web

Structuring Content with Astro Content Collections

· 1 Min. Lesezeit


Content-heavy sites have a predictable failure mode: markdown files multiply, frontmatter grows inconsistent, and one day a missing pubDate breaks the build in production. Astro’s Content Layer API solves this by bringing schema validation to your local files.

Defining a Collection

Collections live in src/content.config.ts. You declare a Zod schema, and Astro validates every file at build time:

import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const blog = defineCollection({
  loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
  schema: z.object({
    title: z.string(),
    pubDate: z.coerce.date(),
    tags: z.array(z.string()),
    draft: z.boolean().default(false),
  }),
});

export const collections = { blog };

If a post is missing title, the build fails with a clear error pointing to the exact file. No more silent frontmatter bugs.

Querying Collections

In any .astro page, getCollection returns fully typed entries:

import { getCollection } from 'astro:content';

const posts = await getCollection('blog', ({ data }) => !data.draft);
posts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());

The filter function strips drafts. The sort gives you newest-first ordering without a plugin.

Rendering MDX

import { render } from 'astro:content';

const { Content, headings } = await render(entry);

headings is a flat array of every heading element in the document — exactly what you need for a table of contents. I’m not using it yet, but it’s there when the time comes.

Static Route Generation

Pairing collections with getStaticPaths keeps routing tight:

export async function getStaticPaths() {
  const posts = await getCollection('blog', ({ data }) => !data.draft);
  return posts.map((post) => ({
    params: { slug: post.id },
    props: { post },
  }));
}

The post.id is derived from the filename (type-safe-apis.mdxtype-safe-apis), so your URLs are stable and predictable without any extra configuration.

Ähnliche Beiträge