Astro Content Collections でブログを構築する
Astro ブログ フロントエンド
Markdownを書くだけでブログができる。frontmatterのtypoや必須項目の漏れはビルド時に検出されるので、本番に載せてから気づく失敗を防げる。必要なのは3つのファイルだけ。
1. スキーマを定義する
src/content/config.ts を作成する。
import { defineCollection, z } from "astro:content";
const blog = defineCollection({
type: "content",
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
tags: z.array(z.string()).default([]),
}),
});
export const collections = { blog };
z.coerce.date() で「2025-02-15」形式を Date 型に変換する。toLocaleDateString() や getTime() が使える。
2. 記事を書く
src/content/blog/hello.mdx を作成する。
---
title: はじめての記事
description: テスト用の記事です。
pubDate: 2025-02-15
tags: ["Astro"]
---
本文。
3. 一覧ページと詳細ページ
一覧(src/pages/blog/index.astro)
---
import { getCollection } from "astro:content";
const entries = await getCollection("blog");
const sorted = entries.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime());
---
<ul>
{sorted.map((entry) => (
<li>
<a href={`/blog/${entry.slug}/`}>{entry.data.title}</a>
<time>{entry.data.pubDate.toLocaleDateString("ja-JP")}</time>
</li>
))}
</ul>
詳細(src/pages/blog/[...slug].astro)
---
import { getCollection } from "astro:content";
export async function getStaticPaths() {
const entries = await getCollection("blog");
return entries.map((entry) => ({
params: { slug: entry.slug },
props: { entry },
}));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<article>
<h1>{entry.data.title}</h1>
<time datetime={entry.data.pubDate.toISOString()}>
{entry.data.pubDate.toLocaleDateString("ja-JP", { year: "numeric", month: "long", day: "numeric" })}
</time>
<Content />
</article>
entry.slug はファイル名から自動生成される(hello.mdx → hello)。MDX 内で Callout や Table を使う場合は、<Content components={mdxComponents} /> でコンポーネントを渡す。
型安全のメリット
titleやdescriptionを忘れるとビルドエラー- 日付の形式が混在するとパースエラー
tagsを文字列で書くと型エラー(配列必須)
よくある落とし穴
- slug を変えたい — frontmatter に
slugを定義し、スキーマでslug: z.string().optional()にする - 複数コレクション —
blogとblog-enを分ける場合、collectionsに両方登録 - MDX のコンポーネント —
<Content components={mdxComponents} />で Callout などを渡す
関連記事
あわせて読むと理解が深まる関連記事をまとめました。
| トピック | 記事 |
|---|---|
| content-visibility: auto 完全ガイド | content-visibility: auto 完全ガイド|遅延レンダリングと長尺ページ最適化 2026 |
| Content Security Policy (CSP) 設定ガイド | Content Security Policy (CSP) 設定ガイド|XSS・クリックジャッキング対策 |
| X-Content-Type-Options: nosniff 解説 | X-Content-Type-Options: nosniff 解説|MIMEスニッフィング対策 |
| React SSR Hydration Mismatch 原因と修正 | React SSR Hydration Mismatch 原因と修正|Next.js・Astro対応ガイド |
| View Transitions API 完全ガイド | View Transitions API 完全ガイド|SPA・MPA ページ遷移と Astro/React 統合 |
| 1フレームは何秒・何ms? 60fpsと120fpsの計算方法 | 1フレームは何秒・何ms? 60fpsと120fpsの計算方法 |
| AIクローラー対応 robots.txt・llms.txt 設定ガイド 2026 | AIクローラー対応 robots.txt・llms.txt 設定ガイド 2026|GPTBot・ClaudeBot・Google-Extended・GEO戦略 |
| APIキャッシュ設計ガイド | APIキャッシュ設計ガイド|ETag・Cache-Control・304・CDNキャッシュキーの実務 |
| Web APIのエラーハンドリング設計 | Web APIのエラーハンドリング設計|RFC 9457・error_code・400/422/409の使い分け |
| Web APIのべき等性(Idempotency)設計 | Web APIのべき等性(Idempotency)設計|二重決済を防ぐ実装ガイド |
| API設計におけるページネーションの使い分け:オフセット型とカーソル型の比較 | API設計におけるページネーションの使い分け:オフセット型とカーソル型の比較 |
| APIのレート制限(Rate Limiting)実装ガイド | APIのレート制限(Rate Limiting)実装ガイド|アルゴリズム選定と429エラーの適切なハンドリング |