Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content Collections guide #2141

Merged
merged 127 commits into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from 71 commits
Commits
Show all changes
127 commits
Select commit Hold shift + click to select a range
d9546c9
new: content collections intro
bholmesdev Dec 5, 2022
a06e06f
draft: paste from RFC initial pass
bholmesdev Dec 5, 2022
d991b50
new: finalize feature walkthrough, add landing pg example
bholmesdev Dec 5, 2022
b03445b
feat: add Rendering Content docs
bholmesdev Dec 5, 2022
55db443
feat: add to nav
bholmesdev Dec 6, 2022
1c57b9c
edit: nested directory and schema
bholmesdev Dec 6, 2022
93bc3a2
new: zod quick reference
bholmesdev Dec 6, 2022
292bc1d
edit: quick reference
bholmesdev Dec 6, 2022
dd70ad2
edit: better intro
bholmesdev Dec 6, 2022
70d7bf9
edit: better Zod onboarding callouts
bholmesdev Dec 6, 2022
ac9e57e
edit: clarify why rendering content is better than body
bholmesdev Dec 6, 2022
936233e
new: Rendering guide for pages
bholmesdev Dec 6, 2022
11a2901
edit: highlight collection names
bholmesdev Dec 6, 2022
3f70af5
edit: remove unneeded optional comment
bholmesdev Dec 6, 2022
7c56330
edit: medium-to-large -> non-trivial
bholmesdev Dec 7, 2022
dd34936
srcDir -> src
bholmesdev Dec 7, 2022
6a8418a
edit: refine glossary
bholmesdev Dec 7, 2022
a393479
edit: tweak CMS and database comparison
bholmesdev Dec 7, 2022
33d0162
adding -> defining a collection
bholmesdev Dec 7, 2022
854ea85
edit: render example lead-in
bholmesdev Dec 7, 2022
64a0d23
edit: injectedFrontmatter destructure clarity
bholmesdev Dec 7, 2022
235b0d7
edit: add filename to render entry example
bholmesdev Dec 7, 2022
b734578
edit: tweak readingTime wording
bholmesdev Dec 7, 2022
67f4eef
edit: simplify schema example
bholmesdev Dec 7, 2022
0ba8392
edit: refine collection-with-dashes ex
bholmesdev Dec 7, 2022
1be56c7
Frontmatter YAML -> Markdown and MDX
bholmesdev Dec 7, 2022
e807849
edit: apparently my dashes aren't cool enough
bholmesdev Dec 7, 2022
14bf265
edit: wording on getCollection types
bholmesdev Dec 7, 2022
650e382
edit: blog -> src/content/blog
bholmesdev Dec 7, 2022
6e04f2e
edit: better directory return type explanation
bholmesdev Dec 7, 2022
3fd4103
nit: indents
bholmesdev Dec 7, 2022
f281d84
edit: subdirectory lead-in
bholmesdev Dec 7, 2022
509934a
edit: en -> en/
bholmesdev Dec 7, 2022
b7d60bf
edit: better file tree
bholmesdev Dec 8, 2022
cd3d071
edit: remove dup file name
bholmesdev Dec 8, 2022
dc56c5c
edit: better filetree on collections example
bholmesdev Dec 8, 2022
98cf092
edit: filetree for docs schema
bholmesdev Dec 8, 2022
6fafee3
edit: refine dynamic route section
bholmesdev Dec 8, 2022
43a2b71
edit: there's always a hippo watching over us
bholmesdev Dec 9, 2022
aa5b091
edit: more context on props -> renderEntry
bholmesdev Dec 9, 2022
8d31687
edit: pass entry as prop key
bholmesdev Dec 9, 2022
bcb3567
edit: getting from -> querying
bholmesdev Dec 9, 2022
194795f
nit: empty line before list
bholmesdev Dec 9, 2022
67052a6
nit: trailing newline
bholmesdev Dec 9, 2022
b493c8a
edit: move type example into other example
bholmesdev Dec 9, 2022
01819fe
edit: getting -> querying
bholmesdev Dec 9, 2022
c8bb5da
edit: Markdown TM
bholmesdev Dec 9, 2022
a53bab5
edit: Sarah lead-in edits
bholmesdev Dec 9, 2022
5b55a4f
edit: better schema config explainer
bholmesdev Dec 9, 2022
11fec3c
edit: remove renderEntry individual args ex
bholmesdev Dec 9, 2022
e8934a7
edit: tweak return type for review
bholmesdev Dec 9, 2022
148fe9a
edit: fine I'll remove the lead-in I spent 15 min debating
bholmesdev Dec 9, 2022
e71465c
edit: org nested dir redraft
bholmesdev Dec 9, 2022
497fcf0
Merge branch 'new/content-schemas-guide' of github.com:withastro/docs…
bholmesdev Dec 9, 2022
5a3f4e1
edit: without a glossary or emojis I'm a shallow husk of a docs writer
bholmesdev Dec 9, 2022
8b5f3a9
edit: work glossary into content dir section
bholmesdev Dec 9, 2022
cc7abca
edit: truncate dashes col name example
bholmesdev Dec 9, 2022
1b92643
edit: break out collection functions to headings
bholmesdev Dec 9, 2022
a2d657c
nit: example -> eg
bholmesdev Dec 9, 2022
634df16
edit: refine generating pages example
bholmesdev Dec 9, 2022
56333d3
edit: redraft why zod sections
bholmesdev Dec 9, 2022
16e94cd
edit: reorder `defineCollection` instructions
bholmesdev Dec 9, 2022
de6de68
edit: return type -> data returned example
bholmesdev Dec 9, 2022
066092f
edit: remove landing page example at end
bholmesdev Dec 9, 2022
3149f64
edit: redraft Collections
bholmesdev Dec 9, 2022
b2bfc83
edit: add homepage preview example to rendering content
bholmesdev Dec 9, 2022
4e43f02
edit: remove dead querying nested dirs link
bholmesdev Dec 9, 2022
e495936
edit: remove redundant link
bholmesdev Dec 9, 2022
e929b03
edit: object keys -> collection names
bholmesdev Dec 9, 2022
957dbf2
fix: broken code comment
bholmesdev Dec 9, 2022
74ebdf8
edit: landing page ex tweak
bholmesdev Dec 9, 2022
5d9c06f
edit: 2 -> two
bholmesdev Dec 10, 2022
6e25027
edit: rogue space
bholmesdev Dec 10, 2022
43c63d4
edit: no fancy apostrophes
bholmesdev Dec 10, 2022
556228c
edit: no fancy apostrophes 2
bholmesdev Dec 10, 2022
649bd0b
edit: include Zod for better SEO
bholmesdev Dec 10, 2022
2159de0
edit: reserved directory -> special
bholmesdev Dec 13, 2022
f60eca1
edit: remove `data`
bholmesdev Dec 13, 2022
083269e
edit: refine collections lead-in
bholmesdev Dec 13, 2022
57f39ee
nit: `renderEntry()`
bholmesdev Dec 13, 2022
20215c4
edit: have a growing number...
bholmesdev Dec 13, 2022
32b98d1
edit: new but also not new collection lead-in
bholmesdev Dec 13, 2022
77c09b3
edit: undead URLs are pages right?
bholmesdev Dec 13, 2022
fecca4c
edit: that's a wee bit bri'ish innit
bholmesdev Dec 13, 2022
c446fe7
edit: remove superfluous file tree
bholmesdev Dec 13, 2022
228b208
edit: trailing /, newline
bholmesdev Dec 13, 2022
0cbce48
edit: clarify schema config
bholmesdev Dec 13, 2022
ebc2f60
edit: well aren't you detail orien`tag`
bholmesdev Dec 13, 2022
6f91765
edit: refine frontmatter prop x data type
bholmesdev Dec 13, 2022
7fae5bd
edit: refine zod schema intro
bholmesdev Dec 13, 2022
5d973ae
edit: whitespace in collection example
bholmesdev Dec 13, 2022
1c4b102
edit: CHRIS? IS THAT AN EMOJI? I'M CALLING THE POLICE 🚔
bholmesdev Dec 13, 2022
b7e3b65
edit: clarify with uncompiled
bholmesdev Dec 13, 2022
ec65b65
edit: refine landing page example (now usage ex)
bholmesdev Dec 13, 2022
dacc5a4
edit: remove unused `tags`
bholmesdev Dec 13, 2022
a59a39a
edit: move "querying nested directories" to `getCollection` docs
bholmesdev Dec 13, 2022
a42ef74
edit: regexcellent catch
bholmesdev Dec 13, 2022
4afbde0
edit: usage example l3 -> l4
bholmesdev Dec 13, 2022
5fc82de
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
9f82c52
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
2fede08
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
e2a4956
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
868ab93
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
b265911
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
3c54672
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
80991fe
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
c26d987
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
cca41b0
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
b70c786
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
84af2d2
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
36f9d68
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
9bd3c71
Update src/pages/en/guides/content-collections.md
bholmesdev Dec 14, 2022
94c53c7
edit: rendering-post-contents rework
bholmesdev Dec 14, 2022
79fb7c5
Extend extensions
delucis Dec 14, 2022
14987a5
2 green bullet points sitting on a wall…
delucis Dec 14, 2022
e05e9f3
new: add experimental note
bholmesdev Dec 15, 2022
dcb7dce
edit: renderEntry -> render
bholmesdev Dec 15, 2022
ee70831
edit: a -> your wording
bholmesdev Dec 16, 2022
0cd4f0f
Spaces
delucis Dec 16, 2022
61c0281
Unmangle before rework
delucis Dec 16, 2022
e9bac98
Rework “rendering content” section
delucis Dec 16, 2022
834adfd
Fix broken fragment link
delucis Dec 16, 2022
b1fbb2f
add parentheses to functions
sarah11918 Dec 16, 2022
8ab0037
strictNullChecks
sarah11918 Dec 16, 2022
adf6e20
Merge branch 'main' into new/content-schemas-guide
delucis Dec 16, 2022
d0ca82c
Use `<FileTree>` :christmas_tree:
delucis Dec 16, 2022
7d7f235
Add Since component
delucis Dec 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/i18n/en/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ export default [
key: 'guides/server-side-rendering',
},
{ text: 'Authoring Content', slug: 'guides/content', key: 'guides/content' },
{
text: 'Content Collections (Experimental)',
slug: 'guides/content-collections',
key: 'guides/content-collections',
},
{ text: 'Connecting a CMS', slug: 'guides/cms', key: 'guides/cms' },
{ text: 'Images', slug: 'guides/images', key: 'guides/images' },
{ text: 'Fonts', slug: 'guides/fonts', key: 'guides/fonts' },
Expand Down
375 changes: 375 additions & 0 deletions src/pages/en/guides/content-collections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,375 @@
---
layout: ~/layouts/MainLayout.astro
title: Content Collections (Experimental)
description: Content collections help organize your Markdown and type-check your frontmatter with schemas.
i18nReady: false
---

Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. Collections may be helpful if you:

- **Plan to use Markdown content in multiple areas** of your site (landing pages, footers, navigation, etc).
- **Have a non-trivial number of documents** to manage and fetch (e.g. a blog with 50+ posts).
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
- **Want Astro to enforce frontmatter fields,** and fail if fields are missing (e.g. every blog post should have a title and description).

## The content directory

Astro provides a reserved directory for Markdown content, `src/content/`. This is where **collections** (folders) of Markdown/MDX **entries** (files) can be stored, with a single configuration file to define each collection's **schema** (frontmatter data types and shape).
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

## Collections

A collection is folder containing Markdown or MDX files whose frontmatter all share the same data shape and types.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

Astro [provides built-in functions](#querying-content-collections) for querying your content data files by collection directory name. This means every content file in `src/content/` **must** belong to a collection directory.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

With this organization, you can retrieve a set of entries based on the collection name, and optionally enforce frontmatter types with a schema.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

To create a new collection, add a new directory to `src/content/`, and add Markdown or MDX entries that share frontmatter properties. The following example shows two collections: `blog` and `newsletter`.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```bash "newsletter/" "blog/"
src/content/
│ # All blog posts have the same frontmatter properties
├── blog/
│ ├── columbia.md
│ ├── endeavour.md
│ └── enterprise.md
│ # All newsletters have the same frontmatter properties
└── newsletter/
├── week-1.md
├── week-2.md
└── week-3.md
```

### Organizing with nested directories
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

Collections are **top-level folders** within `src/content`. You cannot nest collections, but you may use nested directories within a collection to better organize a collection's content. All nested directories will share the same schema defined for the top-level collection.
For example, you can use this structure for internationalization:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```bash
src/content/
└── docs/
│ # docs schema applies to all nested directories 👇
├── en/
├── es/
└── ...
```

All nested directories will share the same schema defined for the top-level collection, if any (**docs** in this example).
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

## Defining a collection schema

Schemas are an optional way to enforce frontmatter types in a collection. Astro uses [Zod](https://github.com/colinhacks/zod) to validate your frontmatter with schemas as [Zod objects](https://github.com/colinhacks/zod#objects).
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

To configure schemas, create a `src/content/config.{js|mjs|ts}` file. This file should:
delucis marked this conversation as resolved.
Show resolved Hide resolved

1. Import the `defineCollection` and `z` utilities from `astro:content`. These are used to define a `schema` for each collection.
2. Export a `collections` object, with each object key corresponding to the collection's folder name.

For example, say you have a `src/content/engineering-blog` collection, where every entry should have a `title`, list of `tags`, and an optional `image` URL. You can specify each expected property like so:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```ts
// src/content/config.ts
import { z, defineCollection } from 'astro:content';

const engineeringBlog = defineCollection({
schema: {
title: z.string(),
image: z.string().optional(),
tags: z.array(z.string()),
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
},
});

export const collections = {
// Don't forget 'quotes' for collection names containing dashes
'engineering-blog': engineeringBlog,
};
```

### Schema data types with Zod

Markdown and MDX frontmatter can contain booleans, strings, numbers, objects, and arrays. Each frontmatter property must be listed in your schema object along with its data type.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

You can extend any of these types with `.optional()` (make property optional) or `.defaultValue(value)` (set a default value). You can also specify a set of allowable values for a frontmatter property using `enum`.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

The following schema illustrates each of these data types in use:

```ts
import { z, defineCollection } from 'astro:content';

defineCollection({
schema: {
isDraft: z.boolean(),
title: z.string(),
sortOrder: z.number(),
image: z.object({
src: z.string(),
alt: z.string(),
}),
tags: z.array(z.string()), // An array of strings
footnote: z.string().optional(),
author: z.string().default('Anonymous'),
language: z.enum(['en', 'es']),
}
})
```

### Advanced schema features

You can use all of Zod’s properties and methods with content schemas. This includes transforming a frontmatter value into another value, checking the shape of string values with built-in regexes, and more.

```ts
{
// Allow only strings representing email addresses
authorContact: z.string().email(),
// Allow URL strings only (e.g. `https://example.com`)
canonicalURL: z.string().url(),
// Parse publishDate as a browser-standard `Date` object
publishDate: z.string().transform(str => new Date(str)),
}
```

See [Zod’s documentation](https://github.com/colinhacks/zod) for a complete list of features.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

## Querying content collections

Astro provides 2 functions to query collections:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

### `getCollection()`

`getCollection()` returns multiple entries in a collection. It requires the name of a `collection` as a parameter. By default, it returns all items in the collection.

It can also take a second, optional parameter: a filter function based on schema properties. This allows you to query for only some items in a collection based on `id`, `slug`, or frontmatter values via the `data` object.

```astro
---
import { getCollection } from 'astro:content';
// Get all `src/content/blog/` entries
const allBlogPosts = await getCollection('blog');
// Only return posts with `draft: true` in the frontmatter
const draftBlogPosts = await getCollection('blog', ({ data }) => {
return data.draft === true;
});
---
```
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

### `getEntry()`

`getEntry()` is function that returns a specific entry in a collection by entry ID (file path relative to the collection). Both of these are required parameters.

```astro
---
import { getEntry } from 'astro:content';

const enterprise = await getEntry('blog', 'enterprise.md');
---
```

### Data returned from a collections query

`getCollection()` and `getEntry()` will return entries that include:
- `id` - a unique ID using the file path relative to `src/content/[collection]`
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
- `slug` - a URL-ready slug. Defaults to the ID without the file extension.
- `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured.
- `body` - a string containing the raw body of the Markdown or MDX document.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

### Landing page example

Given the following collection:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```bash
src/content/
├── blog/
├── columbia.md
├── endeavour.md
└── enterprise.md
```
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
...and the following schema:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```ts
// src/content/config.ts
import { z, defineCollection } from 'astro:content';
const blog = defineCollection({
schema: {
title: z.string(),
tags: z.array(z.string()),
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
status: z.enum(['draft', 'published']).default('draft'),
publishedDate: z.string().transform((str) => new Date(str)),
},
});
export const collections = { blog };
```

You can use `getCollection()` on an index page to retrieve each post's type-safe frontmatter and a `slug` to use for links:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```astro
---
// src/pages/index.astro
import { getCollection } from 'astro:content';

// Get all published blog posts
const blogPosts = await getCollection('blog', ({ data }) => {
return data.status === 'published';
});
---
<ul>
{allBlogPosts.map(post => (
<li>
<a href={post.data.slug}>{post.data.title}</a>
<time datetime={post.data.publishedDate.toISOString()}>
{post.data.publishedDate.toDateString()}
</time>
</li>
))}
</ul>
```

:::tip
Add a filtering function to `getCollections()` to return a subset of a collection's entries. For example, to fetch an entire subdirectory within a collection:

```astro
---
import { getCollection } from 'astro:content';
const enDocs = await getCollection('docs', ({ id }) => {
return id.startsWith('en/');
});
---
```
:::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be directly under the getCollection subheading above? It’s OK here but feels weirder because the example above literally already shows this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this was originally the "querying nested directories" example, but I agree the rephrasing made this unclear. I'd also prefer to bring the "querying nested directories" example back so we have an anchor link to send to people. I've already run into the need for this!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update: moved under the getCollection section with a subheading, and refined the wording


bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
### Collection entry types

If a page or component uses content from a `getCollection()` or `getEntry()` query, you can use the `CollectionEntry` utility to type its props:

```astro /CollectionEntry[(<.+>)?]/
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
---
// src/components/BlogCard.astro
import type { CollectionEntry } from 'astro:content';

interface Props {
// Get type of a `blog` collection entry
post: CollectionEntry<'blog'>;
}

// `post.data` will match your collection schema
const { post } = Astro.props;
---
```

## Rendering content
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

You may need to render the contents of these Markdown and MDX entries as well. This is especially useful when generating live URLs from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), or adding post previews to your homepage.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

You can retrieve a `<Content />` component for use in your Astro files with `renderEntry`. For example, this page will render the contents of `content/announcements/welcome.md`:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```astro "renderEntry"
---
// src/pages/welcome-announcement.astro
import { renderEntry, getEntry } from 'astro:content';
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

const announcementPost = await getEntry('announcements', 'welcome.md');
const { Content } = await renderEntry(announcementPost);
---

<h1>{announcementPost.data.title}</h1>
<Content />
```

### Access content headings

Astro [generates a list of headings](/en/guides/markdown-content/#exported-properties) for Markdown and MDX documents. You can access this list using the `headings` property from `renderEntry`:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```astro "{ headings }"
---
import { getCollection, renderEntry } from 'astro:content';
const blogPosts = await getCollection('blog');
---

{blogPosts.map(async (post) => {
const { headings } = await renderEntry(post);
const h1 = headings.find(h => h.depth === 1);
return <p>{h1}</p>
})}
```

### Access injected frontmatter

Astro allows you to [inject frontmatter using remark or rehype plugins.](/en/guides/markdown-content/#example-injecting-frontmatter) You can access these values using the `injectedFrontmatter` property from `renderEntry`:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```astro "{ injectedFrontmatter }"
---
import { getCollection, renderEntry } from 'astro:content';
const blogPosts = await getCollection('blog');
---

{blogPosts.map(async (post) => {
const { injectedFrontmatter } = await renderEntry(post);
return <p>{post.data.title} — {injectedFrontmatter.readingTime}</p>
})}
```

Assuming `readingTime` was injected ([see our reading time example](/en/guides/markdown-content/#example-calculate-reading-time)), it will be available on the `injectedFrontmatter` object.

<details>
<summary>**🙋 Why don't `getCollection` and `getEntry` contain these values?**</summary>
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
sarah11918 marked this conversation as resolved.
Show resolved Hide resolved

The remark and rehype pipelines are only run when your content is **rendered.** This lets `renderEntry` access anything generated by these plugins like injected frontmatter. To stay performant, `getCollection` and `getEntry` do not have this capability.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

</details>

## Generating pages from content collections

You can create pages from your content collections using [dynamic routes](/en/core-concepts/routing/#dynamic-routes).

Say you have a `src/content/blog/` collection, and you want to map these entries to `/posts/*` URLs. You can create a `posts/[...slug].astro` route using `getStaticPaths` like so:

```astro "{ slug: entry.slug }"
---
// src/pages/posts/[...slug].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const blog = await getCollection('blog');
// Map collection entries to pages
return blog.map(entry => ({
// `entry.slug` is the filename of each blog post with `.md` removed
params: { slug: entry.slug },
}));
}
---
```

This will generate routes for every entry in our collection, mapping each entry’s slug to a URL. For example, an entry at `src/content/blog/hello-world.md` will have a slug of `hello-world`. Because this dynamic route is in `src/pages/posts/`, the final URL will be `/posts/hello-world`.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

### Generating pages with nested directories

If you have a collection with [nested directories](#organizing-with-nested-directories) (e.g. when organising your content by locale) this will be reflected in each entry’s `slug`. For example, the collection entry `blog/en/intro.md` will have a slug of `en/intro`.
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

Using [rest parameters in your dynamic routes](/en/core-concepts/routing/#rest-parameters) like in the example above supports mapping nested slugs out-of-the-box.

### Rendering post contents

When generating pages with a dynamic route, you can pass each collection entry via `props` in your `getStaticPaths()` function. You can then retrieve the entry from `Astro.props` and use `renderEntry` to render its contents:
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved

```astro "renderEntry" "props: entry"
---
// src/pages/blog/[...slug].astro
import { getCollection, renderEntry, CollectionEntry } from 'astro:content';

export async function getStaticPaths() {
const docs = await getCollection('docs');
return docs.map(entry => ({
// Pass blog entry via props
params: { slug: entry.slug, props: { entry } },
}));
}

interface Props {
// Optionally use `CollectionEntry` for type safety
entry: CollectionEntry<'docs'>;
}

const { entry } = Astro.props;
const { Content } = await renderEntry(entry);
---

<h1>{entry.data.title}</h1>
<Content />
```