Pages and routing
Generate static dynamic routes
Return params and optional props from getStaticPaths so Astro can build one page for each data item.
A static site is built ahead of time. So a dynamic route like [slug].astro has to tell Astro every URL it should produce. You do that by exporting a getStaticPaths() function from the page.
Here is src/pages/posts/[slug].astro with two posts:
---
const posts = [
{ slug: 'hello-astro', title: 'Hello Astro' },
{ slug: 'islands', title: 'Understanding islands' }
]
export function getStaticPaths() {
return posts.map(post => ({
params: { slug: post.slug },
props: { post }
}))
}
const { post } = Astro.props
---
<h1>{post.title}</h1>
The function returns an array with one object per page. Each object has two parts.
params identifies the route. { slug: 'hello-astro' } produces /posts/hello-astro/. The keys must match the bracket names in the filename.
props is optional. It carries data straight into that page’s render, where you read it from Astro.props as with any component.
When it runs
During npm run build, Astro calls getStaticPaths() once. Then it renders the page one time for every entry it got back. Two entries, two HTML files:
dist/posts/hello-astro/index.html
dist/posts/islands/index.html
The browser never calls this function. It runs in the build, and it’s gone.
Why pass props
You could skip props and look the post up again inside the component, using Astro.params.slug. It works, but you’d fetch or search the same data twice for every page.
Passing the data through props means the lookup happens once, in getStaticPaths(). My advice is to always do it this way when you already have the data in hand.
What goes in params
Parameter values must be strings, or numbers Astro converts to strings for the URL. A rest parameter like [...slug] also accepts undefined, which matches the empty path.
Keep the URL field separate from the display title. 'Understanding islands' is a title. 'islands' is a slug. Don’t derive one from the other at render time, or a title edit changes a public URL.
The missing entry problem
If a slug is not in the returned array, there is no page for it. A link to /posts/deploying/ becomes a production 404, and the build says nothing, because as far as it knows nothing is wrong.
Try this on your project: add a third post to the array, build, and count the folders under dist/posts/. There should be three. Then remove one entry and build again. Its folder disappears.
Lesson completed