内容集合 Content Collections(content layer)
本教程共 56 篇 · 第 20 篇 · 更新于 2026-08-07 · 约 10 分钟阅读
本节目标:理解 v7 里内容集合是什么,学会用
src/content.config.ts加「加载器」定义集合,分清构建时集合和实时集合两种类型。
博客几十篇、商品几百条、文档上千页——这些内容有个共同点:结构一模一样。每篇都有标题、日期、作者。Astro 专门给这类「成批、同质」的内容准备了一个机制,叫内容集合(content collection)。
Important版本提醒:v5 之后内容集合彻底重构,改用「内容层」(content layer)加「加载器」(loader)的写法。网上不少旧文章还在用旧版
src/content/config.ts(带type: 'content'字段、没有 loader)那套,那是过时的。新的写法一律写在src/content.config.ts,用defineCollection({ loader, schema })。查询函数getCollection、getEntry仍然可用,变的是「集合怎么定义」,不是「怎么查询」。本章全部以 Astro 7.2.0 为准。
内容集合到底解决什么
假设你有十篇 Markdown 博客,放一个文件夹里。不上内容集合,你只能用 import.meta.glob 自己挨个读、自己写类型。文章一多,容易出错,编辑器也没提示。
内容集合把这件事标准化了。你先声明「这一批内容长什么样、从哪来」,Astro 就给你一套专门的查询函数,还能做类型检查和自动补全。写错字段名,编辑器当场报错。
一个集合(collection)就是一组「结构相同」的数据。成员叫「条目」(entry)。条目可以是一堆单独文件(比如 src/blog/ 下每篇一个 .md),也可以是一个 JSON 文件里装着所有数据。
配置写在 content.config.ts
所有内容集合都定义在一个特殊文件里:src/content.config.ts。这个文件位置固定,别放错目录。
// src/content.config.ts
// 1. 从 astro:content 引入工具
import { defineCollection } from 'astro:content';
// 2. 引入加载器
import { glob, file } from 'astro/loaders';
// 3. 引入 Zod(用来定义数据结构)
import { z } from 'astro/zod';
// 4. 给每个集合配「加载器」和「结构定义」
const blog = defineCollection({
loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
}),
});
// 5. 导出 collections 对象,注册你的集合
export const collections = { blog };
五步走:引入工具 → 引入加载器 → 引入 Zod → 给集合配 loader 和 schema → 导出 collections。后面查询内容时,靠的就是这个导出的名字 blog。
schema 这一项可选,但强烈建议写。它用 Zod 定义每条数据的形状,既能校验数据对不对,又能给编辑器提供类型提示。具体怎么写,第 21 章细讲。
加载器是什么
「加载器」(loader)负责去数据源把内容取回来,交给 Astro 用。每个集合都必须配一个 loader。你可以把它想成「数据搬运工」:告诉它去哪搬、搬什么,它就帮你把内容整理好。
Astro 自带两个本地加载器:glob() 和 file()。远程数据要自己写加载器或用社区现成的。
glob 加载器:按目录抓一批文件
glob() 适合「一个文件一条数据」的情况,比如一整个文件夹的博客 Markdown。它按「基准路径」加「匹配规则」把文件全抓进来。
// src/content.config.ts
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/data/blog' }),
});
export const collections = { blog };
base 是内容所在的文件夹,pattern 是匹配哪些文件(**/*.md 表示所有 .md)。每条条目的 id 默认按文件名自动生成,而且 URL 友好(小写、空格变短横线)。
想自定义 id,在文件 frontmatter 里加个 slug 属性就行,类似别的框架的「永久链接」:
---
title: 我的帖子
slug: my-custom-id/supports/slashes
---
正文内容。
如果文件夹里是大写文件名,你又不想被转成小写,可以给 glob() 传一个 generateId 函数,自己决定 id 怎么生成。
file 加载器:从一个文件读多条
file() 反过来:一个文件里装着多条数据。比如一个 dogs.json 里是全部狗狗信息。它支持 JSON、YAML、TOML 格式,会自动解析成多条条目。
// src/content.config.ts
import { defineCollection } from 'astro:content';
import { file } from 'astro/loaders';
const dogs = defineCollection({
loader: file('src/data/dogs.json'),
});
export const collections = { dogs };
文件里的每条数据,必须带一个独一无二的 id 字段,加载器才能辨识和查询。两种写法都行:
[
{ "id": "poodle", "coat": "curly", "shedding": "low" },
{ "id": "afghan", "coat": "short", "shedding": "low" }
]
{
"poodle": { "coat": "curly", "shedding": "low" },
"afghan": { "coat": "silky", "shedding": "low" }
}
遇到 CSV 这类不支持的格式,得给 file() 传一个 parser 解析函数。嵌套的 JSON 也一样,用 parser 把想要的那部分拆出来当集合。
自定义加载器:抓远程数据
内容在本地的,用上面两个够了。数据在远程(比如 CMS、数据库、某个 API 端点),就得写自定义加载器,用内容加载器 API 去取。
// src/content.config.ts
import { defineCollection } from 'astro:content';
import { myLoader } from './loader.ts';
const blog = defineCollection({
loader: myLoader({
url: 'https://api.example.com/posts',
apiKey: 'my-secret',
}),
});
自定义加载器写好了,还能打包发到 npm,给别人用。官方文档的「Content Loader API」里有完整写法示例,需要时照着抄。
Tip社区已经有不少现成加载器,覆盖常见 CMS 和数据源。先去 Astro 集成市场搜
loaders分类,说不定不用自己写。
构建时集合 vs 实时集合
内容集合分两种,按「什么时候取数据」来区分,这点很关键。
构建时集合:数据在「构建网站」那一刻取好,存进内容层的数据仓库。适合博客、文档、商品描述这类相对静态、追求性能的内容。多数网站用这种就够了。
实时集合:数据在「用户每次请求页面」时才去取。适合库存、价格、用户专属数据这类频繁变动、要实时最新的值。代价是每次请求都现取,性能不如构建时。
两种集合用的 API 长得很像(getCollection 对应 getLiveCollection),写起来手感一致。实时集合还有几个限制:不支持 MDX 渲染、不能做图片优化、数据不落盘持久化。
实时集合写在另一个文件 src/live.config.ts,用 defineLiveCollection() 定义,加载器要实现 loadCollection 和 loadEntry 方法,并且必须配「适配器」(adapter)才能按需渲染。
// src/live.config.ts
import { defineLiveCollection } from 'astro:content';
import { storeLoader } from '@mystore/astro-loader';
const products = defineLiveCollection({
loader: storeLoader({
apiKey: process.env.STORE_API_KEY,
endpoint: 'https://api.mystore.com/v1',
}),
});
export const collections = { products };
新手阶段,先把构建时集合玩明白。实时集合等真遇到「数据分钟级变化」的需求再上。
什么时候该用内容集合
满足下面任意一条,就值得上内容集合:
- 有一堆结构相同的文件或数据要管理(比如一目录 Markdown 帖子)。
- 内容存在远程 CMS,想用现成查询函数,而不是自己
fetch。 - 要一次取成千上万条数据,需要能扩展的查询和缓存。
反过来,下面情况就别用:
- 只有一两篇独立内容页,直接写
.astro页面组件更省事。 - 是 PDF 这类 Astro 不处理的文件,丢
public/目录即可。 - 数据源有自己的 SDK,且跟加载器不兼容,你宁愿直接用它的客户端库。
小结
内容集合是 Astro 管理批量同质内容的现代方案。v7 的写法是:在 src/content.config.ts 里用 defineCollection 定义,每个集合必须配一个「加载器」——本地的 glob()、file(),或自己写的远程加载器。集合分构建时和实时两种,绝大多数站点用构建时足矣。
下一步,第 21 章讲怎么用 Zod 给集合定义结构(schema),以及怎么查询和渲染这些集合里的内容。