So far, if we wanted to create a new page, we created a new file: contact.astro, about.astro. This is what we call static routing.
But, what if we have an online store with 300 products? Or a website like this one with over 5,000 articles? It’s not feasible to create 5,000 .astro files by hand.
We need a way to create a template and a mechanism to tell Astro:
Use this template to generate one page for each of the items I tell you
Of course, in Astro the template will be a component, and the mechanism for batch generation is dynamic routes and the getStaticPaths function.
The Bracket Syntax [param]
To generate a dynamic route we use brackets in the filename. Whatever we put inside the brackets will be the name of the variable parameter.
For example, if we create the file: src/pages/product/[id].astro
This file can generate routes like:
/product/1/product/nike-sneakers/product/abc-123
Which routes will it generate? It depends on the possible values for [id], which we define with getStaticPaths 👇
The value that occupies the parameter, in this case [id], will be accessible within the code.
const { id } = Astro.params;
The getStaticPaths Function
Astro cannot guess what IDs your website has. You have to tell it the possible values (for example, what products you have in your database).
For that, we export a mandatory function called getStaticPaths.
Since Astro is (by default) a static site generator (SSG), it needs to know at build time exactly which pages will exist.
The getStaticPaths function only runs when building the site (npm run build). It does not run in the user’s browser.
Let’s see a basic example. Suppose you want to make a website about dogs. One section is about different dog breeds.
So you make a component called src/pages/dogs/[breed].astro:
---
export function getStaticPaths() {
// This function MUST return an array of objects
// Each object represents a page that will be generated
return [
{ params: { breed: 'labrador' } },
{ params: { breed: 'german-shepherd' } },
{ params: { breed: 'poodle' } },
];
}
// To access the parameter of the current URL:
const { breed } = Astro.params;
---
<h1>Information about the {breed}</h1>
In the getStaticPaths function you have specified the three pages you are going to generate.
When building, Astro will generate 3 HTML files:
/dogs/labrador/index.html,/dogs/german-shepherd/index.html/dogs/poodle/index.html
Passing Data with props
The previous example is fine, but it’s a bit “lame”. We’ve generated a page for each dog breed, and we’ve used the [breed] parameter in the component’s text.
But of course, we should get more information about the breed (size, weight, etc.) to display on our website. Do we have to make a second query?
getStaticPaths allows us to pass data to each generated page via the props property.
---
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
// 1. Get ALL articles from our collection
const posts = await getCollection('blog');
// 2. Return a route for each article
return posts.map((post) => {
return {
// params: What goes in the URL (matches the filename [slug])
params: { slug: post.slug },
// props: The complete data we want to pass to the component
props: { post },
};
});
}
// 3. Retrieve the data.
// 'Astro.params' gives us the URL.
// 'Astro.props' gives us the complete object we passed above.
const { post } = Astro.props;
const { Content } = await post.render();
---
<h1>{post.data.title}</h1>
<Content />
This is the standard pattern in Astro: Load the data in getStaticPaths and pass it via props.
This way you avoid having to query the database or file system again inside the component.
Rest Parameters [...path]
Sometimes the URL structure isn’t as simple as /blog/title. Sometimes we need to capture routes with variable depth, like:
/docs/v1/installation/docs/v1/components/buttons
For this we use three dots inside the brackets: [...slug].astro.
This will capture any route that matches that pattern.
---
// src/pages/docs/[...path].astro
export function getStaticPaths() {
return [
{ params: { path: 'v1/intro' } },
{ params: { path: 'v1/advanced/configuration' } },
{ params: { path: undefined } }, // Captures the root /docs
];
}
const { path } = Astro.params;
---
<p>You are viewing the route: {path}</p>
Dynamic Routes vs SSR
It’s important to understand that getStaticPaths is exclusive to Static mode (SSG).
If you configure your project in Server Side Rendering (SSR) mode (which we’ll see in the next module), getStaticPaths becomes unnecessary in most cases.
- In SSG: “Generate these 100 pages now and save them as HTML”. (Needs
getStaticPaths). - In SSR: “Wait for a user to come, see what URL they request (
/product/999), query the database in real time, and generate the HTML on the fly”. (Does not usegetStaticPaths).
