Getting Started with Astro Content Collections

February 1, 2024 6 min read

Astro’s Content Collections provide a powerful way to manage structured content with built-in type safety and validation. This post explores how to migrate from static blog posts to a dynamic, content-driven system.

Content Collections Architecture

Here’s how Content Collections fit into the overall Astro architecture:

Content Files

Content Collections

Schema Validation

Type Generation

getCollection API

Static Site Generation

src/content/blog/*.mdx

src/content/config.ts

TypeScript Types

pages/blog/slug.astro

Built Site

Why Content Collections?

Traditional static blog implementations require creating individual .astro files for each post, making content management cumbersome for non-technical users. Content Collections solve this by:

  • Type Safety: Automatic TypeScript types for your content
  • Content Validation: Schema validation for consistent data
  • Better DX: Hot reload and better IDE support
  • Scalability: Easy to add hundreds of posts without cluttering your pages directory

Setting Up Content Collections

First, create the configuration file that defines your content schema:

// src/content/config.ts
import { defineCollection, z } from "astro:content";

const blogCollection = defineCollection({
  type: "content",
  schema: z.object({
    title: z.string(),
    description: z.string(),
    publishDate: z.date(),
    tags: z.array(z.string()),
    readingTime: z.string(),
    draft: z.boolean().optional().default(false),
    featured: z.boolean().optional().default(false),
  }),
});

export const collections = {
  blog: blogCollection,
};

Creating Dynamic Routes

Replace static blog post files with a dynamic route that handles all posts:

---
// src/pages/blog/[slug].astro
import { getCollection, type CollectionEntry } from "astro:content";
import BlogLayout from "@/layouts/BlogLayout.astro";

export async function getStaticPaths() {
  const posts = await getCollection("blog");

  return posts
    .filter((post: CollectionEntry<"blog">) => !post.data.draft)
    .map((post: CollectionEntry<"blog">) => ({
      params: { slug: post.slug },
      props: { post },
    }));
}

const { post } = Astro.props;
const { Content } = await post.render();
---

<BlogLayout {...post.data}>
  <article class="prose prose-lg mx-auto">
    <Content />
  </article>
</BlogLayout>

Content Organization

Organize your content in the src/content/blog/ directory:

src/content/

config.ts

blog/

getting-started-astro.mdx

content-collections-guide.mdx

advanced-features.mdx

src/content/
├── config.ts
└── blog/
    ├── getting-started-astro.md
    ├── content-collections-guide.md
    └── advanced-features.md

Each markdown file includes frontmatter with the required schema fields:

---
title: "Your Post Title"
description: "A compelling description"
publishDate: 2024-02-01
tags: ["astro", "tutorial"]
readingTime: "5 min read"
---

Your content here...

Benefits of This Approach

  1. Content Management: Non-technical users can add posts by creating markdown files
  2. Type Safety: Automatic validation and TypeScript support
  3. Performance: Only published posts are built into the site
  4. SEO: Proper meta tags and structured data automatically generated
  5. Developer Experience: Hot reload, syntax highlighting, and better tooling

Advanced Features

Content Collections support advanced features like:

  • Content References: Link between different collections
  • Asset Optimization: Automatic image optimization for content images
  • Internationalization: Multi-language content support
  • Custom Renderers: Extend markdown rendering with custom components

contains

has

has

COLLECTION

string

name

string

type

object

schema

ENTRY

string

slug

string

id

object

data

string

body

FRONTMATTER

string

title

date

publishDate

string[]

tags

boolean

draft

CONTENT

string

markdown

string

html

object[]

headings

This system scales from a simple blog to complex content management needs while maintaining excellent developer experience and performance.