情報工学と格闘する
公開

Astro の Content Collections で型安全なブログを作る

Content Collections とは

Astro の Content Collections は、Markdown / MDX ファイルを型安全に管理する仕組みです。Zod スキーマでフロントマターを検証し、TypeScript の型推論が効くようになります。

Content Collections を使うと、記事データの取得時に自動で型が付くため、タイポや型の不一致をビルド時に検出できます。

セットアップ

まず src/content.config.ts でコレクションを定義します。

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

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

export const collections = { blog };

ポイントは z.boolean().default(false) のようにデフォルト値を設定できること。フロントマターに draft を書かなければ自動的に false になります。

記事の取得

コレクションから記事を取得するユーティリティを作ります。

import { getCollection } from "astro:content";

export async function getPublishedPosts() {
  const posts = await getCollection("blog", ({ data }) => {
    return data.draft !== true;
  });

  return posts.sort(
    (a, b) => b.data.date.getTime() - a.data.date.getTime()
  );
}

この関数は以下の2つを行っています:

  1. draft: true の記事を除外する
  2. 日付の降順(新しい順)でソートする

ページでの使用

動的ルーティングで各記事のページを生成します。

---
import { getCollection, render } from "astro:content";

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

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

<article>
  <h1>{post.data.title}</h1>
  <Content />
</article>

post.data.title には自動的に string 型が付きます。スキーマに存在しないプロパティにアクセスしようとすると、TypeScript がエラーを出してくれます。

glob パターンの活用

月別フォルダで記事を管理する場合、**/*.mdx パターンが便利です。

src/content/blog/
├── 2026-01/
│   └── first-post.mdx
├── 2026-02/
│   └── second-post.mdx
└── 2026-03/
    └── third-post.mdx

フォルダ構造に関係なく、すべての .mdx ファイルが再帰的に収集されます。entry.id にはフォルダパスが含まれる(2026-03/third-post)ので、スラッグ生成時にフォルダ部分を除去する処理が必要です。

export function getSlug(id: string): string {
  const parts = id.split("/");
  return parts[parts.length - 1];
}

まとめ

Content Collections を使うメリットは3つです:

  • 型安全: フロントマターの型が自動推論される
  • バリデーション: ビルド時にスキーマ違反を検出できる
  • 柔軟性: glob パターンで自由なファイル構成に対応できる

個人ブログのような小規模なサイトでも、型安全な記事管理は開発体験を大きく改善してくれます。