generateStaticParams
Source URL: https://nextjs.org/docs/app/api-reference/functions/generate-static-params
generateStaticParams
Section titled “generateStaticParams”The generateStaticParams function can be used in combination with dynamic route segments to statically generate routes at build time instead of on-demand at request time.
generateStaticParams can be used with:
- Pages (
page.tsx/page.js) - Layouts (
layout.tsx/layout.js) - Route Handlers (
route.ts/route.js)
// Return a list of `params` to populate the [slug] dynamic segmentexport async function generateStaticParams() { const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({ slug: post.slug, }))}
// Multiple versions of this page will be statically generated// using the `params` returned by `generateStaticParams`export default async function Page({ params,}: { params: Promise<{ slug: string }>}) { const { slug } = await params // ...}// Return a list of `params` to populate the [slug] dynamic segmentexport async function generateStaticParams() { const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({ slug: post.slug, }))}
// Multiple versions of this page will be statically generated// using the `params` returned by `generateStaticParams`export default async function Page({ params }) { const { slug } = await params // ...}Good to know:
- You can use the
dynamicParamssegment config option to control what happens when a dynamic segment is visited that was not generated withgenerateStaticParams.- You must return an empty array from
generateStaticParamsor utilizeexport const dynamic = 'force-static'in order to revalidate (ISR) paths at runtime.- During
next dev,generateStaticParamswill be called when you navigate to a route.- During
next build,generateStaticParamsruns before the corresponding Layouts or Pages are generated.- During revalidation (ISR),
generateStaticParamswill not be called again.generateStaticParamsreplaces thegetStaticPathsfunction in the Pages Router.
Parameters
Section titled “Parameters”options.params (optional)
If multiple dynamic segments in a route use generateStaticParams, the child generateStaticParams function is executed once for each set of params the parent generates.
The params object contains the populated params from the parent generateStaticParams, which can be used to generate the params in a child segment.
Returns
Section titled “Returns”generateStaticParams should return an array of objects where each object represents the populated dynamic segments of a single route.
- Each property in the object is a dynamic segment to be filled in for the route.
- The properties name is the segment’s name, and the properties value is what that segment should be filled in with.
| Example Route | generateStaticParams Return Type |
|---|---|
/product/[id] | { id: string }[] |
/products/[category]/[product] | { category: string, product: string }[] |
/products/[...slug] | { slug: string[] }[] |
Single Dynamic Segment
Section titled “Single Dynamic Segment”export function generateStaticParams() { return [{ id: '1' }, { id: '2' }, { id: '3' }]}
// Three versions of this page will be statically generated// using the `params` returned by `generateStaticParams`// - /product/1// - /product/2// - /product/3export default async function Page({ params,}: { params: Promise<{ id: string }>}) { const { id } = await params // ...}export function generateStaticParams() { return [{ id: '1' }, { id: '2' }, { id: '3' }]}
// Three versions of this page will be statically generated// using the `params` returned by `generateStaticParams`// - /product/1// - /product/2// - /product/3export default async function Page({ params }) { const { id } = await params // ...}Multiple Dynamic Segments
Section titled “Multiple Dynamic Segments”export function generateStaticParams() { return [ { category: 'a', product: '1' }, { category: 'b', product: '2' }, { category: 'c', product: '3' }, ]}
// Three versions of this page will be statically generated// using the `params` returned by `generateStaticParams`// - /products/a/1// - /products/b/2// - /products/c/3export default async function Page({ params,}: { params: Promise<{ category: string; product: string }>}) { const { category, product } = await params // ...}export function generateStaticParams() { return [ { category: 'a', product: '1' }, { category: 'b', product: '2' }, { category: 'c', product: '3' }, ]}
// Three versions of this page will be statically generated// using the `params` returned by `generateStaticParams`// - /products/a/1// - /products/b/2// - /products/c/3export default async function Page({ params }) { const { category, product } = await params // ...}Catch-all Dynamic Segment
Section titled “Catch-all Dynamic Segment”export function generateStaticParams() { return [{ slug: ['a', '1'] }, { slug: ['b', '2'] }, { slug: ['c', '3'] }]}
// Three versions of this page will be statically generated// using the `params` returned by `generateStaticParams`// - /product/a/1// - /product/b/2// - /product/c/3export default async function Page({ params,}: { params: Promise<{ slug: string[] }>}) { const { slug } = await params // ...}export function generateStaticParams() { return [{ slug: ['a', '1'] }, { slug: ['b', '2'] }, { slug: ['c', '3'] }]}
// Three versions of this page will be statically generated// using the `params` returned by `generateStaticParams`// - /product/a/1// - /product/b/2// - /product/c/3export default async function Page({ params }) { const { slug } = await params // ...}Examples
Section titled “Examples”Static Rendering
Section titled “Static Rendering”All paths at build time
Section titled “All paths at build time”To statically render all paths at build time, supply the full list of paths to generateStaticParams:
export async function generateStaticParams() { const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({ slug: post.slug, }))}export async function generateStaticParams() { const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({ slug: post.slug, }))}Subset of paths at build time
Section titled “Subset of paths at build time”To statically render a subset of paths at build time, and the rest the first time they’re visited at runtime, return a partial list of paths:
export async function generateStaticParams() { const posts = await fetch('https://.../posts').then((res) => res.json())
// Render the first 10 posts at build time return posts.slice(0, 10).map((post) => ({ slug: post.slug, }))}export async function generateStaticParams() { const posts = await fetch('https://.../posts').then((res) => res.json())
// Render the first 10 posts at build time return posts.slice(0, 10).map((post) => ({ slug: post.slug, }))}Then, by using the dynamicParams segment config option, you can control what happens when a dynamic segment is visited that was not generated with generateStaticParams.
// All posts besides the top 10 will be a 404export const dynamicParams = false
export async function generateStaticParams() { const posts = await fetch('https://.../posts').then((res) => res.json()) const topPosts = posts.slice(0, 10)
return topPosts.map((post) => ({ slug: post.slug, }))}// All posts besides the top 10 will be a 404export const dynamicParams = false
export async function generateStaticParams() { const posts = await fetch('https://.../posts').then((res) => res.json()) const topPosts = posts.slice(0, 10)
return topPosts.map((post) => ({ slug: post.slug, }))}All paths at runtime
Section titled “All paths at runtime”To statically render all paths the first time they’re visited, return an empty array (no paths will be rendered at build time) or utilize export const dynamic = 'force-static':
export async function generateStaticParams() { return []}Good to know:
- You must always return an array from
generateStaticParams, even if it’s empty. Otherwise, the route will be dynamically rendered.
export const dynamic = 'force-static'With Cache Components
Section titled “With Cache Components”When using Cache Components with dynamic routes, generateStaticParams must return at least one param. Empty arrays cause a build error. This allows Cache Components to validate your route doesn’t incorrectly access cookies(), headers(), or searchParams at runtime.
Good to know: If you don’t know the actual param values at build time, you can return a placeholder param (e.g.,
[{ slug: '__placeholder__' }]) for validation, then handle it in your page withnotFound(). However, this prevents build time validation from working effectively and may cause runtime errors.
See the dynamic routes section for detailed walkthroughs.
With Route Handlers
Section titled “With Route Handlers”You can use generateStaticParams with Route Handlers to statically generate API responses at build time:
export async function generateStaticParams() { return [{ id: '1' }, { id: '2' }, { id: '3' }]}
export async function GET( request: Request, { params }: RouteContext<'/api/posts/[id]'>) { const { id } = await params // This will be statically generated for IDs 1, 2, and 3 return Response.json({ id, title: `Post ${id}` })}export async function generateStaticParams() { return [{ id: '1' }, { id: '2' }, { id: '3' }]}
export async function GET(request, { params }) { const { id } = await params // This will be statically generated for IDs 1, 2, and 3 return Response.json({ id, title: `Post ${id}` })}Route Handlers with Cache Components
Section titled “Route Handlers with Cache Components”When using Cache Components, combine with use cache for optimal caching:
export async function generateStaticParams() { return [{ id: '1' }, { id: '2' }, { id: '3' }]}
async function getPost(id: Promise<string>) { 'use cache' const resolvedId = await id const response = await fetch(`https://api.example.com/posts/${resolvedId}`) return response.json()}
export async function GET( request: Request, { params }: RouteContext<'/api/posts/[id]'>) { const post = await getPost(params.then((p) => p.id)) return Response.json(post)}See the Route Handlers documentation for more details.
Disable rendering for unspecified paths
Section titled “Disable rendering for unspecified paths”To prevent unspecified paths from being statically rendered at runtime, add the export const dynamicParams = false option in a route segment. When this config option is used, only paths provided by generateStaticParams will be served, and unspecified routes will 404 or match (in the case of catch-all routes).
Multiple Dynamic Segments in a Route
Section titled “Multiple Dynamic Segments in a Route”You can generate params for dynamic segments above the current layout or page, but not below. For example, given the app/products/[category]/[product] route:
app/products/[category]/[product]/page.jscan generate params for both[category]and[product].app/products/[category]/layout.jscan only generate params for[category].
There are two approaches to generating params for a route with multiple dynamic segments:
Generate params from the bottom up
Section titled “Generate params from the bottom up”Generate multiple dynamic segments from the child route segment.
// Generate segments for both [category] and [product]export async function generateStaticParams() { const products = await fetch('https://.../products').then((res) => res.json())
return products.map((product) => ({ category: product.category.slug, product: product.id, }))}
export default function Page({ params,}: { params: Promise<{ category: string; product: string }>}) { // ...}// Generate segments for both [category] and [product]export async function generateStaticParams() { const products = await fetch('https://.../products').then((res) => res.json())
return products.map((product) => ({ category: product.category.slug, product: product.id, }))}
export default function Page({ params }) { // ...}Generate params from the top down
Section titled “Generate params from the top down”Generate the parent segments first and use the result to generate the child segments.
// Generate segments for [category]export async function generateStaticParams() { const products = await fetch('https://.../products').then((res) => res.json())
return products.map((product) => ({ category: product.category.slug, }))}
export default function Layout({ params,}: { params: Promise<{ category: string }>}) { // ...}// Generate segments for [category]export async function generateStaticParams() { const products = await fetch('https://.../products').then((res) => res.json())
return products.map((product) => ({ category: product.category.slug, }))}
export default function Layout({ params }) { // ...}A child route segment’s generateStaticParams function is executed once for each segment a parent generateStaticParams generates.
The child generateStaticParams function can use the params returned from the parent generateStaticParams function to dynamically generate its own segments.
// Generate segments for [product] using the `params` passed from// the parent segment's `generateStaticParams` functionexport async function generateStaticParams({ params: { category },}: { params: { category: string }}) { const products = await fetch( `https://.../products?category=${category}` ).then((res) => res.json())
return products.map((product) => ({ product: product.id, }))}
export default function Page({ params,}: { params: Promise<{ category: string; product: string }>}) { // ...}// Generate segments for [product] using the `params` passed from// the parent segment's `generateStaticParams` functionexport async function generateStaticParams({ params: { category } }) { const products = await fetch( `https://.../products?category=${category}` ).then((res) => res.json())
return products.map((product) => ({ product: product.id, }))}
export default function Page({ params }) { // ...}Notice that the params argument can be accessed synchronously and includes only parent segment params.
For type completion, you can make use of the TypeScript Awaited helper in combination with either Page Props helper or Layout Props helper:
export async function generateStaticParams({ params: { category },}: { params: Awaited<LayoutProps<'/products/[category]'>['params']>}) { const products = await fetch( `https://.../products?category=${category}` ).then((res) => res.json())
return products.map((product) => ({ product: product.id, }))}Good to know:
fetchrequests are automatically memoized for the same data across allgenerate-prefixed functions, Layouts, Pages, and Server Components. Reactcachecan be used iffetchis unavailable.
Version History
Section titled “Version History”| Version | Changes |
|---|---|
v13.0.0 | generateStaticParams introduced. |