Skip to content

Astro Dynamic Routes — Parameters and Static Generation

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Astro Dynamic Routes. We cover key concepts, practical examples, and best practices to help you master this topic.

Learn Astro dynamic routes: define parameters with brackets, generate static paths, use catch-all routes, and pass data to page components.

In this lesson, you'll create dynamic routes using [param].astro syntax, implement getStaticPaths() for static generation, and handle catch-all and nested dynamic parameters.

What You'll Learn

How to define dynamic route parameters, generate static paths at build time, access params in page components, and use rest parameters for catch-all routes.

Why It Matters

Dynamic routes let you create pages for each item in a dataset without writing individual files. A single template generates hundreds or thousands of pages.

Real-World Use

DodaTech's tutorial site uses a single dynamic route [slug].astro to render thousands of tutorial pages from content collection entries.

flowchart LR
    A[Product Data] --> B[getStaticPaths]
    B --> C["[id].astro Template"]
    C --> D[/products/1/]
    C --> E[/products/2/]
    C --> F[/products/3/]
    style B fill:#ff5a03,color:#fff

Basic Dynamic Route

Create src/pages/products/[id].astro:

---
export async function getStaticPaths() {
  const products = [
    { id: "1", name: "Widget" },
    { id: "2", name: "Gadget" },
    { id: "3", name: "Doohickey" },
  ];
  return products.map(product => ({
    params: { id: product.id },
    props: { product },
  }));
}

const { product } = Astro.props;
---
<html>
<body>
  <h1>{product.name}</h1>
  <p>Product ID: {product.id}</p>
</body>
</html>

Output: Astro generates three pages at /products/1/, /products/2/, and /products/3/. Each page contains the product data passed as props.

Dynamic Routes with Content Collections

Combine dynamic routes with content collections:

---
import { getCollection } from "astro:content";

export async function getStaticPaths() {
  const posts = await getCollection("blog");
  return posts.map(post => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await post.render();
---
<article>
  <h1>{post.data.title}</h1>
  <Content />
</article>

Output: A page is generated for every entry in the "blog" content collection at /blog/entry-slug/.

Multiple Parameters

Use multiple brackets for nested params:

---
// src/pages/products/[category]/[id].astro
export async function getStaticPaths() {
  const products = [
    { category: "electronics", id: "1", name: "Laptop" },
    { category: "electronics", id: "2", name: "Phone" },
    { category: "books", id: "3", name: "Guide" },
  ];
  return products.map(product => ({
    params: { category: product.category, id: product.id },
    props: { product },
  }));
}

const { product } = Astro.props;
---
<h1>{product.name}</h1>
<p>Category: {product.category}</p>

Output: /products/electronics/1/, /products/books/3/, etc.

Catch-All Routes

Use [...slug].astro for catch-all routes:

---
// src/pages/docs/[...slug].astro
export async function getStaticPaths() {
  const docs = [
    { slug: "getting-started", title: "Getting Started" },
    { slug: "guides/installation", title: "Installation Guide" },
    { slug: "guides/advanced/config", title: "Configuration" },
  ];
  return docs.map(doc => ({
    params: { slug: doc.slug },
    props: { doc },
  }));
}

const { doc } = Astro.props;
const segments = Astro.params.slug;
// segments is a string for single-level, or array for nested
---
<h1>{doc.title}</h1>

Output: /docs/getting-started/, /docs/guides/installation/, /docs/guides/advanced/config/.

Rest Parameters

Use [[...slug]].astro for optional catch-all (matches / too):

---
// src/pages/[[...path]].astro
export async function getStaticPaths() {
  return [
    { params: { path: undefined }, props: { page: "home" } },
    { params: { path: ["about"] }, props: { page: "about" } },
    { params: { path: ["blog", "post-1"] }, props: { page: "post" } },
  ];
}

const { page } = Astro.props;
---
<h1>{page}</h1>

Output: / matches the root, /about/ matches single-level, /blog/post-1/ matches nested paths.

Common Mistakes

  1. Forgetting getStaticPaths() in dynamic routes: Astro requires getStaticPaths() for dynamic routes in static mode. Without it, the build fails.
  2. Returning mismatched params: The params object keys must match the bracket names in the filename. [id].astro needs params: { id: ... }.
  3. Not handling empty catch-all segments: When [[...slug]].astro matches /, slug is undefined. Check for it before using.
  4. Over-generating pages: If getStaticPaths() returns thousands of paths, build time increases. Use SSR mode for very large datasets.
  5. Mixing dynamic and static files in the same directory: A [slug].astro file and a fixed.astro file in the same directory can conflict. Keep dynamic routes in separate directories.

Practice Questions

  1. What function generates paths for dynamic routes? Answer: getStaticPaths(). It returns an array of { params, props } objects.

  2. How do you access route parameters in the page component? Answer: Through Astro.params or Astro.props (if passed from getStaticPaths).

  3. What is the difference between [...slug] and [[...slug]]? Answer: [...slug] requires at least one segment. [[...slug]] is optional and matches the root path too.

  4. Can dynamic routes use content collections? Answer: Yes. Query collections in getStaticPaths() and pass the entries as props.

Challenge

Create a dynamic route for a "products" content collection with nested categories and product IDs. Generate pages at /products/category-name/product-name/.

Mini Project

Build a documentation site with a catch-all route [...slug].astro that renders Markdown files from a content collection. Include breadcrumb navigation based on the slug segments.

FAQ

Can I use dynamic routes with SSR?

: Yes. In SSR mode, getStaticPaths() is optional. Astro handles dynamic params at request time.

How many paths can `getStaticPaths()` return?

: There's no hard limit, but each path adds to build time. For 10,000+ paths, consider SSR or ISR.

What happens if a dynamic route has no matching path?

: In static mode, a 404 page is served. In SSR mode, you can throw a 404 response.

Can I use TypeScript for route params?

: Yes. Define param types with export interface Params { slug: string }.

What's Next

Learn about Astro SSR Modes to understand server-side rendering, static generation, and hybrid approaches.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro