How to Create Dynamic Pages for Your Books with Astro
In this guide, you’ll learn how to build individual pages for each book in your collection using Astro. We’ll cover setting up dynamic routes, fetching book data, and displaying your markdown content.
Overview
You’ve already set up your Astro project to use markdown files for your book content. You can see a list of your books, and each book has a link pointing to a specific page like /books/your-book-id. However, clicking these links currently leads to a 404 error because those pages don’t exist yet. This tutorial will show you how to create those pages automatically for every book in your collection. You’ll learn to make a special page that Astro can use to build unique pages for each book, showing its title and all its detailed content.
Prerequisites
- An existing Astro project.
- Your book content organized in markdown files within a collection (e.g., a
src/content/books/folder). - Basic understanding of Astro components and front matter.
Steps
Create the Dynamic Route File
First, you need to create a new page component that Astro will use for your individual book details. Inside your
src/pages/books/folder, create a new file. The name of this file is important for creating dynamic routes. To make a part of the URL dynamic, you need to put it in square brackets. For example, name the file[id].astro. This tells Astro that theidpart of the URL (like/books/assassin-apprentice) can change for each book.Define Static Paths
Astro needs to know which specific pages to build when you use a dynamic route. You tell Astro this by exporting a special function called
getStaticPathsfrom your page component’s front matter. This function should return an array of objects. Each object in the array tells Astro about one page to create. For every book you have, you’ll need one object in this array.The
getStaticPathsfunction needs to beasyncbecause it will fetch your book data. Inside this function, use Astro’sgetCollectionfunction to get all your books. You’ll need to importgetCollectionfromAstro:content.Here’s how you get your books:
const books = await getCollection('books');. This gives you an array where each item is an object representing one of your books.Map Books to Page Paths
Now, you need to transform the list of books into the array of objects that
getStaticPathsexpects. You can do this by using the.map()method on yourbooksarray. For each book, you’ll return an object with two main properties:paramsandprops.The
paramsobject tells Astro what value to use for the dynamic part of your URL. In our case, the dynamic part isid, so you’ll setparams: { id: book.id }. Thebook.idhere refers to the unique identifier for each book, which usually comes from its filename.The
propsobject is used to pass data directly into your page component. You can pass the entire book object here so your page component has all the book’s information. So, you’ll setprops: { book: book }.Your
getStaticPathsfunction will look something like this:import { getCollection } from 'astro:content'; export async function getStaticPaths() { const books = await getCollection('books'); return books.map(book => ({ params: { id: book.id }, props: { book } })); }Create the Page Component Structure
Next, you’ll build the actual page component using the data passed from
getStaticPaths. Your[id].astrofile will receive thebookobject as a prop. You can access it by destructuring it fromAstro.props.Start by importing your base layout component, just like you would for any other page. Then, wrap your content within a container, perhaps a
<div class="content">, to ensure consistent styling. For now, you can display the book’s title using an<h2>tag:{book.data.title}
. Remember that
book.dataholds the front matter information from your markdown file.Display Markdown Content
Your markdown files contain more than just front matter; they have the actual book descriptions and details. To render this markdown content as HTML within your page, Astro provides a special
Contentcomponent. You need to import therenderfunction fromAstro:content.Inside your page component, you’ll call
render(), passing the content entry (yourbookprop) to it. This function returns a component that contains all your markdown content, already converted into HTML elements like headings, paragraphs, lists, and more. You can then render thisContentcomponent directly in your template.Replace the
<h2>tag with theContentcomponent like this:// At the top of your [id].astro file import { Content} from 'astro:content'; // Inside your component's return statementWhen Astro builds these pages, it automatically converts markdown headings into
<h>tags with corresponding IDs, and markdown lists into<ul>or<ol>tags, making your content structured and accessible.Test Your Dynamic Pages
Save your
[id].astrofile. Now, if you visit the links for your books (e.g.,/books/your-book-id), you should see the individual book pages loading correctly. The title should appear, and below it, all the content from your markdown file will be displayed as formatted HTML. Try clicking on different book links to ensure each one generates a unique page with its correct information.
Expert Notes
The [id].astro filename is a convention. You could use [slug].astro or any other name within the brackets, as long as it matches the parameter name you expect in your route and in the params object within getStaticPaths. The book.id used in params: { id: book.id } is automatically generated by Astro based on the filename of your markdown file (e.g., assassin-apprentice.md would have an ID of assassin-apprentice).
Source: Astro Crash Course #10 – Dynamic Routes (YouTube)