astro-rutas-dinamicas-getstaticpaths

Dynamic Routes and getStaticPaths in Astro

  • 5 min

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;
Copied!

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>
Copied!

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 />
Copied!

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>
Copied!

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 use getStaticPaths).