Rutas dinámicas

Cómo crear rutas flexibles y variables


Hasta ahora, sólo hemos visto como crear rutas simples con Astro, sin embargo, Astro permite crear rutas dinámicas, un tipo de ruta más potente y flexible para hacer cosas algo más avanzadas.

¿Qué son las rutas dinámicas?

Con las rutas estáticas, cada fichero .astro equivale a una única ruta concreta. Sin embargo, con las rutas dinámicas podemos crear un fichero .astro que se encargue de crear múltiples rutas.

Imagina que tenemos una lista de usuarios y queremos hacer una zona de usuarios en nuestra web. Hacer manualmente una página para cada usuario sería muy tedioso. Realmente, la página va a ser la misma, sólo que utilizará los datos de cada usuario en cada página. En ese caso, nos interesa hacer una ruta dinámica: creamos sólo una página y le pasamos la lista de usuarios para que cree una ruta por cada uno.

En Astro podemos crear una página dinámica estableciendo un nombre de fichero con corchetes, por ejemplo, src/pages/users/[username].astro. En este caso, username será el parámetro que usaremos para identificar el nombre de cada usuario.

Al generar las rutas, [username] se reemplazará por el nombre de cada usuario:

src/pages/users/[username].astro

/users/manzdev.html
/users/felixicaza.html
/users/blursoul_.html
/users/pheralb.html
...

¿Y cómo conseguimos estas rutas en Astro? Vamos a verlo.

La función getStaticPaths()

Como hemos mencionado, el primer paso es nombrar nuestra carpeta o fichero con un nombre entre corchetes. Una vez hecho esto, nuestra página .astro debe tener también una función exportada llamada getStaticPaths(), que es la que se utiliza para generar las rutas.

Observa que la función getStaticPaths() está devolviendo un de que tienen una serie de parámetros, donde estamos indicando uno concretamente: username con el nombre de cada usuario:

---
export function getStaticPaths() {
  return [
    { params: { username: "manzdev" }},
    { params: { username: "felixicaza" }},
    { params: { username: "blursoul_" }},
    { params: { username: "pheralb" }},
  ];
}

const { username } = Astro.params;
---
<h1>{username}</h1>

Luego, obtenemos el username de Astro.params, que es donde se guardan los parámetros. Astro procesará de forma previa todos estos parámetros y generará una página para cada ruta, pasándole la información en cuestión.

Ahora, en lugar de indicar los nombres de usuario manualmente, vamos a automatizarlos y recogerlos de una estructura de datos que sea más fácil de modificar. Observa que ahora partimos de un users con los nombres:

---
const users = ["manzdev", "felixicaza", "blursoul_", "pheralb"];

export function getStaticPaths() {
  return users.map(username => {
    return { params: { username }}
  });
}

const { username } = Astro.params;
---
<h1>{username}</h1>

En el interior de la función getStaticPaths() procesamos ese y devolvemos el que esta función espera, un objeto con params. Aunque no lo hemos hecho aún, junto a los params podríamos añadir props con información adicional para añadir.

Vamos ahora un paso más allá. En el fichero src/data/users.json tenemos un de donde cada objeto tiene información sobre un usuario: rol, imagen, color, etc... Importamos esa información a un objeto en Astro y lo utilizamos en la función getStaticPaths():

---
import users from "../data/users.json";

export async function getStaticPaths() {
  return users.map(({ username, role, image, color }) => {
    return {
      params: { username },
      props: { role, image, color }
    }
  });
}

const { username } = Astro.params;
const { role, image, color } = Astro.props;
---
<h1>{username}</h1>
[
  {
    username: "ManzDev",
    role: "streamer",
    image: "/assets/manzdev.avif",
    color: "indigo",
    ...
  },
  ...
]

Observa que con el .map() recorremos todos los usuarios creamos un objeto con los parámetros que forman parte de la URL (username) y el resto de parámetros que los pasamos como props para que estén disponibles en la parte inferior del frontmatter del componente de .astro.

Esto nos permite crear múltiples páginas que dependan de información externa sin tener que crear las páginas una a una.

Múltiples niveles

En el caso que necesitemos múltiples niveles de rutas dinámicas, podemos resolverlo utilizando [] en las carpetas y ficheros necesarios. Por ejemplo, imaginemos que queremos la siguiente estructura:

/post/2025/astro-el-mejor-framework
/post/2025/bienvenidos
/post/2024/se-viene-2025
/post/2024/himno-a-clippy
...
src/pages/post/[year]/[slug].astro

Observa que en esta ocasión vamos a crear múltiples niveles y nos interesa que las rutas estén siempre en una carpeta /post/, seguidas del año en cuestión y de el título del post, que llamaremos slug.

Vamos ahora con el contenido de nuestro fichero src/pages/post/[year]/[slug].astro:

---
import posts from "../../../data/posts.json";

export async function getStaticPaths() {
  return posts.map(post => ({
    params: {
      year: post.year,
      slug: post.slug
    },
    props: {
      post
    }
  }));
}

const { post } = Astro.props;
const { year, slug } = Astro.params;
---
<h1>{post.title}</h1>
<p>{post.content}</p>
<small>Publicado en: {year} - URL: /post/{year}/{slug}</small>
  • 1️⃣ Empezamos importando todo desde el fichero posts.json.
  • 2️⃣ Creamos una función getStaticPaths() que devuelve un de .
  • 3️⃣ Mapeamos el posts y devolvemos params (parte de la URL) y props (info)
  • 4️⃣ Utilizamos las variables en nuestro marcado para crear la página.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev