Astro
Astro getStaticPaths, explained simply
Written by Noel
Published:
18 min read
Topics researched with AI assistance; reviewed and edited by Noel before publishing.

Explore this topic
More Astro guides, glossary entries, and practical workflows live on the topic hub.
Astro getStaticPaths is the function you use to tell Astro which dynamic pages to generate during a static build. If a route file uses brackets, such as [slug].astro or [category]/[product].astro, Astro needs a complete list of parameter values before it can write the final pages.
That matters because it turns a route pattern into real URLs without runtime guessing. A blog, product catalog, or documentation site can ship as static HTML while still supporting hundreds or thousands of unique pages.
Key takeaways
- Dynamic filenames define the route shape; getStaticPaths supplies the actual values.
- Every params object must match the route file names exactly, including multiple parameters.
- Static builds need the full route list up front; SSR does not use getStaticPaths.
- props can carry page-specific data into the template, which keeps page code cleaner.
- Rest parameters let one route file cover nested paths, but they need careful data shaping.
What is it?
Astro getStaticPaths is a function exported from a dynamic page file that returns the set of route parameters Astro should build. In static output mode, Astro cannot guess which pages should exist from a filename alone, so getStaticPaths acts as the source of truth for those pages.
A simple example is a file like src/pages/dogs/[dog].astro. The filename says the route has one dynamic segment, but it does not say which dog pages exist. getStaticPaths might return params for clifford, rover, and spot, and Astro will generate /dogs/clifford, /dogs/rover, and /dogs/spot.
The important part is that the route file and the params object must agree. If the filename uses [dog], the returned params must include dog. If the filename uses [lang]/[version]/info.astro, the returned params must include both lang and version for each generated route.
In practice, this is the bridge between content data and URLs. A merchant might have a collection of landing pages for product categories, while a developer might have a docs site with one page per API reference entry. getStaticPaths lets both teams keep the content structured while still serving static pages.
It is also worth separating the route definition from the page content. The filename defines the URL shape, but getStaticPaths defines the actual instances of that shape. That distinction is what makes Astro’s static routing feel predictable: the route is not discovered at request time, it is assembled from known data during the build.
Why it matters — business and technical impact
For merchants and developers, the business value of astro getStaticPaths is predictability. When pages are generated at build time, the site can be fast, cacheable, and easier to reason about. You know which URLs exist before deployment, which helps with content planning, QA, and SEO checks.
That predictability also reduces runtime work. Instead of asking the server to discover every route on each request, Astro can write the pages ahead of time. For content-heavy sites, that often means simpler hosting and fewer moving parts when traffic spikes.
There is also a search and operations angle. Static pages are easier to audit for broken links, duplicate routes, and missing content. If your site structure depends on a CMS, product catalog, or content collections, getStaticPaths gives you a controlled way to translate records into pages.
The technical impact is just as important. Dynamic routes are powerful, but they can become fragile if the route data is inconsistent. A missing param, an unexpected slug format, or a mismatch between filenames and returned objects can break builds. Once the pattern is understood, though, getStaticPaths becomes a reliable foundation for large static sites.
For teams shipping content at scale, this also improves collaboration. Editors can think in terms of records and slugs, while developers can think in terms of route files and templates. getStaticPaths is the contract between those two views. When that contract is clear, it becomes easier to add new content types, reorganize sections, or localize pages without changing the overall rendering model.
A practical business benefit is release confidence. If the route list is generated from a known source, you can review the output before launch and catch missing pages before users do. That is especially useful for seasonal campaigns, documentation updates, and catalog refreshes where one broken URL can affect both traffic and trust.
Another reason it matters is that it keeps performance decisions visible. If a page must be prebuilt, the team has to decide that intentionally instead of letting routing behavior drift over time. That creates a cleaner architecture review: static pages for stable content, SSR for request-driven content, and a clear boundary between the two. In larger teams, that boundary prevents accidental complexity, such as adding live data dependencies to a page that was supposed to stay static.
How it works — explain the mechanism step by step
Astro routing starts with the file system. A page file inside src/pages/ becomes a route, and bracketed segments mark dynamic parts of the path. A file named [slug].astro can match many URLs, but only if Astro knows which slugs to build.
The build process then calls getStaticPaths. That function returns an array of objects, and each object includes a params property. Those params values are inserted into the route pattern, one generated page per object.
If the route file includes multiple dynamic segments, each params object must include every required key. For example, a route like [lang]/[version]/info.astro needs both lang and version. If you return only one of them, Astro does not have enough information to create the page.
Astro also supports rest parameters such as […slug].astro. That pattern is useful when one file needs to match nested paths of different depths. In that case, the slug value can represent a single segment, multiple segments, or even be undefined for the top-level page, depending on how you shape the returned data.
A useful detail from the routing model is that getStaticPaths can also return props. Those props are passed into the page component and can hold page-specific data like titles, descriptions, or preloaded content. That keeps the template focused on rendering instead of doing repeated lookups.
The mechanism is easiest to understand as a three-step handoff: the filename declares the route pattern, getStaticPaths supplies the list of valid parameter values, and the page template renders each generated route using Astro.params and Astro.props. If any of those three pieces disagree, the build fails or the output is incomplete.
In real projects, that handoff often starts with a data source such as a CMS export, a JSON file, or a content collection. The route function reads the records, filters them, and maps each one into a params object. If the page needs more than the URL, the same loop can attach props so the template does not need to repeat the lookup. That separation keeps route generation deterministic and makes the page easier to maintain later.
A second mechanism to understand is that the build output is fixed once the function runs. That means the route list is not a live query against your content source; it is a snapshot of the data at build time. If the source changes later, the generated pages do not change until the next build. For many teams that is a feature, not a limitation, because it makes deployments repeatable and easier to verify.
Use cases — where teams actually apply this
The most common use case is a content site with one page per record. Think of a blog, a documentation portal, or a resource library where each item has a slug. getStaticPaths turns the list of records into a list of pages, which is exactly what static generation is good at.
A second use case is product or category landing pages. A merchant may want one page for each category, collection, or campaign variant. When those routes are known ahead of time, getStaticPaths makes it easy to keep the URLs clean and the pages fast.
A third use case is multilingual or multi-version content. If your site has routes like /en/v1/info and /fr/v2/info, getStaticPaths can generate the combinations you need from a structured data source. That is especially helpful when the same template needs to serve multiple locales or documentation versions.
Content-driven pages
When content comes from a CMS or a local content layer, getStaticPaths is the piece that maps records to URLs. The route file defines the pattern, and the data source defines the actual pages. This is a natural fit for editorial sites where new entries are added regularly but still published in batches.
Catalog or landing pages
For commerce or portfolio sites, route generation can mirror the catalog structure. A category page, a service page, or a showcase page can each have its own slug. If you already think in terms of records and slugs, getStaticPaths keeps the implementation aligned with that mental model.
Nested and hierarchical routes
Rest parameters are useful when the path depth is not fixed. A knowledge base, a file browser, or a nested product taxonomy may need URLs that are one level deep in some cases and three levels deep in others. getStaticPaths can handle that, but only if the returned params are shaped carefully.
A useful decision rule is to choose getStaticPaths when the page list is finite and the URL structure is stable. Avoid it when the route space is effectively open-ended, such as user-generated paths, live search results, or permission-based pages that should only exist after a request is authenticated. In those cases, SSR or another on-demand pattern is usually a better fit.
How to implement or apply it — practical guidance
Start by deciding whether the route list is known at build time. If it is, static generation is a good fit. If the route list depends on request-time personalization, live inventory, or constantly changing data, you may need SSR instead.
Next, make the route file match the content model. If your data has a single slug field, use [slug].astro. If your data has hierarchical fields, use multiple route segments. The filename should reflect the shape of the data rather than forcing the data to fit an awkward route.
Then write getStaticPaths so it returns a clean array of params objects. Keep the values simple and consistent. If your source data includes encoded values or special characters, normalize them before returning the params so the generated URLs are stable and readable.
A practical pattern is to separate data preparation from rendering. Build the route list first, then pass any extra page data through props. That makes the template easier to test because the page component only consumes Astro.params and Astro.props.
If you are using rest parameters, decide how you want the top-level route to behave. Astro supports undefined for the rest parameter when you want the file to match the base path. That is useful for pages like /sequences as well as /sequences/one/two/three.
A good implementation workflow is to prototype with a small data set first, then expand to the full collection once the route shape is proven. That helps you catch naming mismatches early, especially when you have multiple dynamic segments or nested paths. It also makes it easier to see whether props should carry extra content or whether the page can derive everything from the URL and a single lookup.
When the source data lives in a CMS or API, treat the route list as build input and validate it before generation. Check that every record has a slug, that slugs are unique, and that any nested path segments are in the right order. If the data source can produce drafts or unpublished items, filter them out before getStaticPaths returns the final array. That keeps preview content from leaking into production URLs.
A simple implementation checklist:
- Confirm the route is static-generation friendly.
- Match each dynamic filename segment with a params key.
- Return one object per page you want Astro to build.
- Use props when the page needs extra data beyond the URL.
- Test nested and top-level rest-parameter routes separately.
- Rebuild when the source data changes, because the route list is part of the build output.
- Validate slugs for uniqueness, readability, and URL safety before the build runs.
If you are deciding between params and props, use params for anything that identifies the route and props for anything that only helps render the page. For example, a slug belongs in params, while a title, summary, or hero image can live in props. That keeps the route contract small and makes it easier to refactor the template later without changing the URL structure.
One more practical implementation tip is to keep the route-generation code close to the data source, but not tangled with presentation logic. If the same content collection feeds multiple pages, create a small helper that returns normalized route records. Then each page can map those records into its own params and props shape. That reduces duplication and makes it easier to reuse the same source data for indexes, detail pages, and localized variants.
Common mistakes and pitfalls
The first common mistake is a params mismatch. If the filename is [dog].astro, returning { params: { slug: "spot" } } will not work because Astro expects dog, not slug. The key names must match the filename segments exactly.
The second mistake is assuming getStaticPaths is a runtime hook. It is not. In static mode, it runs at build time, so it cannot depend on request-specific data. If you need a route to exist for any incoming value, that is a different rendering model.
Another pitfall is overusing rest parameters when a simpler route would be clearer. A catch-all route can solve many problems, but it can also hide structure. If your content has a stable hierarchy, explicit segments are usually easier to maintain and debug.
Teams also run into issues when they forget that the route list must be complete. If a new content item is added after the build, it will not appear until the site is rebuilt. That is fine for many editorial and catalog workflows, but it is a constraint you need to plan around.
Finally, encoded or unusual path values can create confusion. Astro notes that params returned from getStaticPaths are not decoded, so if your source data contains encoded characters, you need to handle that intentionally. Otherwise, the generated URL may not match the human-readable path you expected.
A related mistake is mixing concerns inside getStaticPaths. If the function becomes a place for formatting, filtering, fetching, and rendering decisions all at once, it gets harder to debug. Keep the function focused on route generation, and move reusable data shaping into helper functions when the logic starts to grow.
One more practical issue is forgetting to test the empty or root case for rest routes. If […slug].astro is meant to serve both /sequences and deeper paths, verify that undefined is handled on purpose and that the template still renders a sensible base page. That small test often prevents confusing 404s or duplicate content later.
A simple fix pattern helps here: when a build fails, check the filename first, then the params keys, then the data source. In many cases the bug is not in Astro itself but in a mismatch between the content model and the route model. If you correct the model, the code usually becomes simpler as a side effect.
Best practices and quick checklist
The best approach is to treat getStaticPaths as part of your content architecture, not just a routing utility. The cleaner your data model, the simpler your route generation will be. That usually means one canonical slug field, predictable naming, and a clear rule for nested paths.
Keep the route file and data source in sync. If content editors can rename slugs, make sure the build process and internal links are updated together. If you rely on a CMS, content collections, or a product feed, verify that the source data always returns the fields your route expects.
Use props for anything that is not part of the URL itself. The URL should identify the page; props should provide the template with supporting data. That separation makes the route easier to understand and reduces repeated lookups inside the page body.
When you are deciding between static generation and SSR, ask two questions: can I know the route list before build time, and do I want the page to be cached as a static file? If the answer is yes to both, getStaticPaths is usually the right tool.
A practical rule of thumb: use getStaticPaths when the route list is finite, stable enough for builds, and valuable to pre-render. Avoid it when the route space is effectively unbounded, user-specific, or driven by request-time permissions. That decision alone prevents a lot of unnecessary complexity.
Quick checklist:
- Match every param name to the route filename.
- Return a full route list for static builds.
- Use props for extra page data.
- Prefer simple slugs over clever path logic.
- Test nested routes, top-level routes, and edge cases separately.
- Rebuild whenever the source data changes.
- Keep route generation separate from presentation logic.
A final best-practice habit is to document the route contract near the data source. If a collection field feeds a dynamic route, note which field is required, how it is normalized, and whether it can change after publication. That documentation helps editors, developers, and QA teams avoid accidental URL drift.
Another useful habit is to compare the generated route list against your sitemap or navigation before release. That catches missing pages, duplicate slugs, and accidental exclusions early. If your site has multiple locales or versions, review each set separately so one language does not silently drift from the others.
From practice — illustrative scenario (hypothetical, not a client project)
Illustrative example — not a real client project: imagine a merchant building a small Astro-powered catalog for downloadable templates and guides. The site has a landing page, a category page for each template type, and a detail page for every item. The content lives in a structured data source with fields like slug, category, title, and summary.
At first, the team might be tempted to hardcode links and page files manually. That works for five pages, but it becomes brittle when the catalog grows. A new item means another file, another route, and another chance to mistype a URL. The team also wants the pages to stay fast and easy to deploy on static hosting.
A more practical approach is to create a dynamic route file for the detail pages, such as [slug].astro, and use getStaticPaths to return one params object per item. The function can read the catalog data, map each record to a slug, and pass the title and summary through props. The page template then renders the shared layout while each generated page gets its own URL and content.
If the catalog also needs category pages, the team can use a second dynamic route like [category].astro or a nested structure if the hierarchy is deeper. The key decision is to keep the route shape aligned with the content model. That way, the build output stays predictable even as the catalog grows.
A sensible workflow would be to define the data schema first, then write a small route-generation helper, then test the output URLs against a short list of expected pages. If the team later adds filters like featured, draft, or seasonal, those can be handled before the params array is returned. That keeps the routing layer clean and makes it obvious which records are meant to ship.
The takeaway is not that getStaticPaths is complicated. The takeaway is that it rewards structure. When the content is organized first, Astro can turn that structure into pages with very little runtime overhead. When the content is messy, the route function becomes a cleanup layer, which is usually a sign the data model needs work.
A second hypothetical workflow makes the tradeoff clearer. Suppose the same team wants a localized version of the catalog with English and French routes. Instead of creating separate page files for every language, they can generate combinations in getStaticPaths from a single source of truth. The route helper can loop through each item and each locale, return the matching params, and attach locale-specific copy through props. That reduces duplication and keeps translation work separate from route design.
In review, the team would check three things before shipping: whether every generated URL matches the intended structure, whether the base route and nested routes both render correctly, and whether unpublished items are excluded from the build. Those checks are simple, but they are exactly the kind of details that prevent broken navigation later.
A useful decision point in this scenario is what should happen when a record changes. If a title changes but the slug stays the same, the page can rebuild without affecting links. If the slug changes, the team needs a redirect plan so old URLs do not break. That is why route design should be discussed alongside content governance, not after launch. The more stable the slug policy, the less maintenance the static site needs over time.
Related concepts and further reading
If you are working through dynamic routes in Astro, these guides help connect the routing model to real site architecture.
- Astro content collections guide — useful when your route data comes from organized content sources.
- Astro islands architecture — helpful context for how Astro keeps pages fast after build.
- Astro Themes — browse starter themes that can benefit from structured dynamic routing.
- Astro docs routing guide — the official reference for route files, params, and static generation.
Explore this topic
More Astro guides, glossary entries, and practical workflows live on the topic hub.
Frequently asked questions
What does astro getStaticPaths do?
astro getStaticPaths tells Astro which dynamic routes to generate at build time. It returns an array of route parameter objects, and each object becomes one generated page. This is how a file like [slug].astro can produce many pages without needing runtime route discovery.
When should I use getStaticPaths instead of SSR?
Use getStaticPaths when the full set of routes is known during the build, such as blog posts, product pages, or documentation pages. Use SSR when routes depend on request-time data or when the route list changes too often to rebuild for every update. The key decision is whether you can safely precompute the URLs ahead of time.
Can getStaticPaths return extra data?
Yes. In Astro, getStaticPaths can return props alongside params, and those props are then available in the page through Astro.props. That is useful when you want to pass preselected content, titles, or lookup results into the template without repeating the lookup logic in the component body.
Do I need getStaticPaths for every dynamic route?
No. You only need it for dynamic routes in static generation mode. If your site runs in SSR or on-demand rendering, the route can be matched at request time and getStaticPaths should not be used.
What is the most common mistake with getStaticPaths?
The most common mistake is returning params that do not match the dynamic filename exactly. If the file is [dog].astro, each object must include dog in its params. Another frequent issue is forgetting that all routes must be known at build time in static mode.