Dynamic routes
A dynamic route is a page where part of the address changes: /posts/first-post, /posts/learning-astro. The parameter is written in the file name in square brackets. Since a static site is built ahead of time, Astro must know every possible value of the parameter, and the getStaticPaths() function returns them.
The post page
Delete src/pages/posts/first-post.astro and create src/pages/posts/[id].astro:
---
import { getCollection, render } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { id: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await render(post);
---
<BaseLayout title={post.data.title}>
<h1>{post.data.title}</h1>
<p>{post.data.pubDate.toLocaleDateString('en-US')}</p>
<Content />
</BaseLayout>Open /posts/first-post and /posts/learning-astro: both pages are built from one file. Links to them are already in the /posts list.
How it works
getStaticPaths() returns an array of objects, one per page:
| Field | What it holds |
|---|---|
params | Address parameter values: { id: 'first-post' } gives /posts/first-post |
props | Data the page receives in Astro.props |
Parameter values are also available in Astro.params, for example Astro.params.id. During the build Astro calls the function once and creates an HTML file for every element of the array.
A tag page
The same technique builds tag pages. Create src/pages/tags/[tag].astro:
---
import { getCollection } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import PostCard from '../../components/PostCard.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog');
const tags = [...new Set(posts.flatMap((post) => post.data.tags))];
return tags.map((tag) => ({
params: { tag },
props: { posts: posts.filter((post) => post.data.tags.includes(tag)) },
}));
}
const { tag } = Astro.params;
const { posts } = Astro.props;
---
<BaseLayout title={`Tag ${tag}`}>
<h1>Posts tagged "{tag}"</h1>
{posts.map((post) => <PostCard title={post.data.title} url={`/posts/${post.id}`} />)}
</BaseLayout>Set removes duplicates, and each tag gets its own page. Open /tags/astro and only posts tagged astro are there. A post can link to a tag with <a href={'/tags/' + tag}>.
Several segments
A parameter with three dots, [...slug].astro, captures an address of any depth: /docs/a/b/c. It is used when entries live in nested folders.
Common mistake
People put a value into params that does not match the links on the site, such as a post title with spaces instead of the id. The page is built at one address while links point to another, and the visitor sees a 404. Use the same field, post.id, both in getStaticPaths() and in links.