#Props in dynamic routes
12 messages · Page 1 of 1 (latest)
Great question! The approach shown in the documentation—passing all posts to every route and then filtering them in the component—is a simple way to ensure that each tag page has access to the full list of posts, so it can display only those relevant to the current tag. This method works, but as you noticed, it’s not the most efficient: each page receives all posts, even though it only needs a subset.
The documentation later introduces a more advanced and efficient approach: filter the posts inside getStaticPaths() so that each route only receives the posts relevant to its tag. This way, you avoid passing unnecessary data to each page. Here’s how that looks:
export async function getStaticPaths() {
const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
const uniqueTags = [...new Set(allPosts.map((post: any) => post.frontmatter.tags).flat())];
return uniqueTags.map((tag) => {
const filteredPosts = allPosts.filter((post: any) => post.frontmatter.tags.includes(tag));
return {
params: { tag },
props: { posts: filteredPosts },
};
});
}
With this pattern, each tag page receives only the posts it needs, making your build more efficient and your code cleaner. The initial approach (passing all posts) is simpler for beginners to understand, but filtering in getStaticPaths() is the recommended best practice as your project grows in size and complexity Advanced JavaScript: Generate pages from existing tags | Final code sample.
So, to answer your question: you don’t have to add all posts to every route. It’s better to filter them in getStaticPaths() and only pass the relevant posts to each page. The documentation shows both methods, but the filtered approach is more efficient.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@storm wharf Kapa.ai is still learning and improving, please let me know how I did by reacting below.
What is the typescript type for allPosts?
const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
@thin panther ?
Let me check the knowledge base for you again. One moment! :books:
You're correct in your observation: it is not necessary to add all posts to every route. The documentation initially demonstrates passing all posts to every tag page for simplicity, but it later shows a more efficient approach—filtering the posts in getStaticPaths() so that each route only receives the posts relevant to its tag.
Here's the improved pattern from the documentation:
export async function getStaticPaths() {
const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
const uniqueTags = [...new Set(allPosts.map((post: any) => post.frontmatter.tags).flat())];
return uniqueTags.map((tag) => {
const filteredPosts = allPosts.filter((post: any) => post.frontmatter.tags.includes(tag));
return {
params: { tag },
props: { posts: filteredPosts },
};
});
}
This way, each tag page only receives the posts it needs, making your build more efficient. The initial approach (passing all posts) is simpler for beginners, but filtering in getStaticPaths() is the recommended and more scalable solution as your project grows see documentation.
So, you are right: you should ideally only add the posts relevant to each route, and the documentation does show this as the best practice.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@storm wharf Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@thin panther What is the typescript type for allPosts?
const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
Let me check the knowledge base for you again. One moment! :books:
The TypeScript type for allPosts when using
const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
is an array of MarkdownInstance<T>, where T is the type of your frontmatter.
From the documentation:
export interface MarkdownInstance<T extends Record<string, any>> {
frontmatter: T;
file: string;
url: string | undefined;
Content: AstroComponentFactory;
rawContent(): string;
compiledContent(): string;
getHeadings(): Promise<{ depth: number; slug: string; text: string }[]>;
default: AstroComponentFactory;
}
You can specify the type like this:
import type { MarkdownInstance } from 'astro';
interface Frontmatter {
title: string;
description?: string;
// add other frontmatter fields as needed
}
const allPosts = Object.values(
import.meta.glob<MarkdownInstance<Frontmatter>>('../posts/*.md', { eager: true })
);
So, the type of allPosts is:
MarkdownInstance<Frontmatter>[]