Astro shows “getStaticPaths() function required for dynamic routes” when a page with brackets in its file name, such as src/pages/blog/[slug].astro, is prerendered but doesn’t export a getStaticPaths() function. Astro builds static pages ahead of time, so it needs a list of every value [slug] can take. Fix it by exporting getStaticPaths(), or, if the page should render per request, by adding export const prerender = false with an adapter installed.
Key Takeaways
- Every prerendered dynamic route needs an exported
getStaticPaths().- The function must be exported:
export async function getStaticPaths().- On-demand pages don’t need it; they read
Astro.paramsat request time.- The full error text is: “
getStaticPaths()function is required for dynamic routes. Make sure that youexportagetStaticPaths()function from your dynamic route.”
Why it happens
Static output is the default in Astro. For a static file name like about.astro, Astro knows the URL. For [slug].astro, it doesn’t know which pages to build until you tell it. The three usual causes:
- The function is missing entirely.
- It exists but isn’t exported (
async function getStaticPaths()withoutexport). - You meant the page to be server-rendered but never opted it out of prerendering.
Fix 1: export getStaticPaths()
---
// src/pages/blog/[slug].astro
import { getCollection, render } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { slug: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await render(post);
---
<h1>{post.data.title}</h1>
<Content />
Each returned object builds one page. The keys in params must match the bracket names in the file name, and their values must be strings.
Fix 2: render the page on demand
If the values come from a database or API and change too often to rebuild, render the route per request instead:
---
// src/pages/products/[id].astro
export const prerender = false;
const { id } = Astro.params;
const product = await fetch(`https://api.example.com/products/${id}`).then((r) => r.json());
---
<h1>{product.name}</h1>
This needs an adapter (npx astro add node, cloudflare, netlify or vercel). Without one you’ll get a different error, covered in Cannot use server-side rendering without an adapter. The hybrid rendering tip explains mixing static and on-demand pages.
Fix 3: check the file name
A bracket in a folder name makes every page inside it dynamic. src/pages/[lang]/about.astro needs getStaticPaths() returning every lang, even though about is static. If the brackets were a mistake, rename the file or folder.
How to confirm it’s fixed
Run npm run build. Astro lists every generated route. Your dynamic pages should appear once per entry, for example /blog/first-post/index.html. If a URL you expect is missing, see No static path found for requested path.
For the bigger picture of dynamic routes, pagination and endpoints, read the Astro routing guide. The official entry for this error is in the Astro error reference.
FAQ
Do I need getStaticPaths() in Astro SSR?
No. Pages with export const prerender = false, or all pages when output: 'server' is set, read Astro.params at request time and must not rely on getStaticPaths().
Can getStaticPaths() be a regular function instead of async?
Yes. It can be synchronous or async, as long as it is exported and returns an array.