The one idea — a typed gateway to your content
A content collection is a typed gateway to your content: define a
Zod schema, point a loader at
your files (or remote data), get fully-typed queries via getCollection() — no more
any frontmatter. Astro 5's Content Layer unifies local
+ remote behind the same API.
1 · the config — src/content.config.ts (Astro 5 moved it here from src/content/config.ts)
Define each collection with defineCollection(), give it a required loader and an optional Zod schema, then export a single collections object.
2 · the content — src/content/blog/*.md
The glob() loader ingests each .md as an entry: an auto-generated
id (kebab-cased from the filename), the parsed data (your frontmatter), and the raw body.
Click an entry to load it into the validator below.
3 · schema validation — a live Zod-style safeParse()
A schema mismatch is a build error, not a runtime one — Astro refuses to ship
an entry whose frontmatter fails safeParse(). Toggle a field below to break/fix the selected entry and watch the
simulated parse result flip. (This is a faithful inline simulation of Zod's required/string/array/boolean rules.)
4 · the data flow — pick a loader
The Content Layer unifies local and remote: swap the loader and
getCollection('blog') keeps the exact same typed shape. You are never limited to .md/.mdx.
src/content/config.ts → src/content.config.ts ·
type:'content'+dir → a required loader · entry.slug → entry.id ·
entry.render() → standalone render(entry) · content can live anywhere (no longer pinned to src/content/).
Cross-refs (🔗): astro_routing_layouts (collections feed dynamic routes via getStaticPaths) · astro_islands (rendered MDX entry as a hydrated island).