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 detalles algo más avanzados.
¿Qué son las rutas dinámicas?
Con las rutas estáticas, cada fichero .astro
genera una única página para una ruta concreta. Sin embargo, con las rutas dinámicas podemos crear un fichero .astro
que se encargará de crear múltiples páginas para varias rutas diferentes.
Imagina que tenemos una lista de usuarios y queremos hacer una página de perfil de usuario para cada uno. Hacer manualmente una página para cada usuario sería muy tedioso, sobre todo en el caso que tengamos muchos usuarios. La página realmente va a ser la misma, sólo que utilizará los datos de cada usuario en cada página concreta. Sería suficiente crear una página «molde» que se usará como base para insertar en ella los datos de cada usuario y generar diferentes páginas.
Archivos de páginas [dinámicas]
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
Esta página generará las siguientes rutas:
/users/manzdev.html
/users/felixicaza.html
/users/blursoul_.html
/users/pheralb.html
...
¿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 exportar una función llamada getStaticPaths()
, que es la que se utiliza para generar las rutas.
Recuerda que Astro, por defecto, no trabaja en la web alojada. Trabaja en desarrollo y genera las páginas estáticas que luego son las que subimos a un servidor. La función
getStaticPaths()
se ejecuta en nuestro equipo cuando hacemos unnpm run build
, y no en el servidor.
Esta función debe devolver una lista de objetos que contenga los parámetros de la ruta dinámica: en nuestro ejemplo, el username
, que es el que forma parte de la URL. Sin esta función getStaticPaths()
nuestra ruta dinámica no funcionará y dará error.
Veamos como implementar la función getStaticPaths()
:
La función getStaticPaths()
debe devolver un /users/[username]
:
---
export function getStaticPaths() {
return [
{ params: { username: "manzdev" }},
{ params: { username: "felixicaza" }},
{ params: { username: "blursoul_" }},
{ params: { username: "pheralb" }},
];
}
const { username } = Astro.params;
---
<h1>{username}</h1>
En este caso, lo que estamos indicando es que vamos a generar 4 páginas estáticas. Una por cada objeto del [username]
de la URL por el username
que le devolvemos en el objeto params
.
Por otro lado, en el contenido de la página, podemos obtener los valores desde Astro.params
, y así poderlos utilizar en la propia página para mostrar o traernos más contenido relacionado.
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 separar (y modificar en el futuro). 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 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 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} ({role}, {color})</h1>
<img src={image} alt={username} />
[
{
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.
Páginas con múltiples niveles
Creando páginas dinámicas, nos puede interesar crear rutas con múltiples niveles. Cuando decimos «múltiples niveles» nos referimos que hay varias secciones entre slash /
, como podemos ver en estos ejemplos:
/post/2025/astro-el-mejor-framework
/post/2025/bienvenidos
/post/2024/se-viene-2025
/post/2024/himno-a-clippy
Observa que tenemos un primer nivel post
, un segundo nivel que es el año, y un tercer nivel que es el título de la página. En el caso que necesitemos estos múltiples niveles de rutas dinámicas, podemos resolverlo utilizando []
en las carpetas y varias veces, no sólo en el fichero como hicimos más atrás.
Para el ejemplo anterior bastaría con crear una ruta dinámica src/pages/post/[year]/[slug].astro
:
- 1️⃣ Las rutas estarán siempre en una carpeta
/post/
. Este es fijo. - 2️⃣ Luego, una carpeta para el año, que llamaremos
[year]
. - 3️⃣ En su interior, tendremos un fichero llamado
[slug].astro
, para los títulos.
Esto proporciona a Astro la suficiente información para saber que las rutas tendrán dos parámetros: el año con [year]
y el título del post con [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 toda la información relevante desde el fichero
src/data/posts.json
. - 2️⃣ Creamos una función
getStaticPaths()
que devuelve unde . - 3️⃣ Mapeamos el array
posts
y devolvemosparams
(parte de la URL) yprops
(info). - 4️⃣ Utilizamos las variables en nuestro marcado para crear la página.
Observa la siguiente tabla y ten en cuenta que puedes crear todo tipo de combinaciones alternativas para crear múltiples rutas dinámicas:
Ruta dinámica | Ruta generada |
---|---|
src/pages/users/[username].astro | /users/manzdev/ |
src/pages/post/[date]-[slug].astro | /post/2025-07-24-mi-primer-post |
src/pages/post/[year]/[month]/[slug].astro | /post/2025/07/mi-primer-post |
src/pages/post/[...path].astro | /post/2025/07/mi-primer-post |
Parámetros complejos
Si te fijaste en la última fila de la tabla anterior, probablemente te habrá extrañado un poco esta ruta dinámica. En este caso estamos utilizando el operador ...
(spread) para obtener múltiples niveles en un sólo parámetro.
En este caso, el parámetro path
va a capturar el texto de la ruta completa: 2025/07/mi-primer-post
. Luego, nosotros podemos separarlo por /
y trabajar con sus partes individuales:
---
export function getStaticPaths() {
return [
{ params: { path: "2025/06/bienvenidos" }},
{ params: { path: "2025/06/mi-primer-post" }}
]
}
const [ year, month, slug ] = Astro.params.path.split("/");
---
<ul>
<li>Year: {year}</li>
<li>Month: {month}</li>
<li>Slug: {slug}</li>
</ul>
Esto podría ser especialmente interesante en algunos casos donde quieres trabajar con el path conjunto para simplificar la obtención de información.