Category: guide
Astro Content Collections — คู่มือฉบับใช้งานจริง
คู่มือการใช้ Content Collections ใน Astro 6 สำหรับจัดการเนื้อหาแบบ type-safe ด้วย Zod schema พร้อม patterns ที่ใช้บ่อยในโปรเจคจริง
สารบัญ
Content Collections คืออะไร
Content Collections คือระบบจัดการเนื้อหาใน Astro ที่ให้คุณเขียน Markdown แล้วได้ TypeScript type safety มาฟรี — frontmatter ผิดรูปแบบ = build ไม่ผ่าน
การตั้งค่าใน Astro 6
ใน Astro 6 ไฟล์ config ย้ายมาที่ src/content.config.ts (ไม่ใช่ src/content/config.ts อีกต่อไป)
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
date: z.date(),
tags: z.array(z.string()).default([]),
status: z.enum(['draft', 'published']).default('draft'),
image: z.string().optional(),
}),
});
export const collections = { blog };
Query ข้อมูล
ดึงทั้งหมด
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
// กรอง draft ออก
const published = posts.filter(p => p.data.status === 'published');
// เรียงตามวันที่ล่าสุด
const sorted = published.sort((a, b) =>
b.data.date.getTime() - a.data.date.getTime()
);
---
Dynamic routes (Static Paths)
---
// src/pages/blog/[slug].astro
import { getCollection, render } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map(post => ({ params: { slug: post.id } }));
}
const { slug } = Astro.params;
const posts = await getCollection('blog');
const post = posts.find(p => p.id === slug);
if (!post) throw new Error(`Post not found: ${slug}`);
const { Content } = await render(post);
---
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
Zod Schema Patterns ที่ใช้บ่อย
const schema = z.object({
// Required
title: z.string().min(1),
date: z.date(),
// Optional พร้อม default
tags: z.array(z.string()).default([]),
status: z.enum(['active', 'completed', 'archived']).default('active'),
// Optional ไม่มี default
image: z.string().optional(),
url: z.string().url().optional(),
// Coerce string → date (กรณี frontmatter เป็น string)
updatedAt: z.coerce.date().optional(),
});
ข้อดีที่ได้จริง
- TypeScript autocomplete ใน frontmatter และหน้า Astro
- Build-time validation — frontmatter ผิด = error ชัดเจน ไม่ใช่ runtime bug
- ไม่ต้องเขียน type แยก —
z.infer<typeof schema>ให้ type อัตโนมัติ - glob loader — เพิ่มไฟล์ markdown = เพิ่ม content ได้เลย ไม่ต้อง register
ข้อควรระวัง
YAML dates เป็น UTC — date: 2026-06-01 ใน frontmatter คือ UTC midnight ถ้า format โดยไม่ระบุ timezone จะแสดงวันผิดสำหรับ UTC+7 ให้เพิ่ม timeZone: 'Asia/Bangkok' ใน Intl.DateTimeFormat
Astro 6 ย้าย config — ถ้าอ่าน tutorial เก่า อาจเห็น src/content/config.ts ซึ่งใช้ไม่ได้ใน Astro 6 แล้ว