gavmac00/nextjs-app-docs huggingface dataset:
During next dev, generateStaticParams will be called when you navigate to a route.
During next build, generateStaticParams runs before the corresponding Layouts or Pages are generated.
During revalidation (ISR), generateStaticParams will not be called again.
generateStaticParams replaces the getStaticPaths function in the Pages Router.
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
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.
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 RoutegenerateStaticParams Return Type/product/[id]{ id: string }[]/products/[category]/[product]{ category: string, product: string }[]/products/[...slug]{ slug: string[] }[]
Single Dynamic Segment
app/product/[id]/page.tsx 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/3
// - /product/2
// - /product/3
export default function Page({ params }: { params: { id: string } }) {
  const { id } = params
  // ...
}
Multiple Dynamic Segments
app/products/[category]/[product]/page.tsx 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/3
export default function Page({
  params,
}: {
  params: { category: string; product: string }
params,
}: {
  params: { category: string; product: string }
}) {
  const { category, product } = params
  // ...
}
Catch-all Dynamic Segment
app/product/[...slug]/page.tsx 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/3
export default function Page({ params }: { params: { slug: string[] } }) {
  const { slug } = params
  // ...
}
Examples
Multiple Dynamic Segments in a Route
// ...
}
Examples
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.js can generate params for both [category] and [product].
app/products/[category]/layout.js can 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
Generate multiple dynamic segments from the child route segment.
app/products/[category]/[product]/page.tsx // 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,
return products.map((product) => ({
    category: product.category.slug,
    product: product.id,
  }))
}
 
export default function Page({
  params,
}: {
  params: { category: string; product: string }
}) {
  // ...
}
Generate params from the top down
Generate the parent segments first and use the result to generate the child segments.
app/products/[category]/layout.tsx // 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: { category: string } }) {
  // ...
}
// ...
}
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.
app/products/[category]/[product]/page.tsx // Generate segments for [product] using the `params` passed from
// the parent segment's `generateStaticParams` function
export 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,
}: {
}))
}
 
export default function Page({
  params,
}: {
  params: { category: string; product: string }
}) {
  // ...
}
Good to know: When rendering a route, Next.js will automatically deduplicate fetch requests for the same data across generateMetadata, generateStaticParams, Layouts, Pages, and Server Components. React cache can be used if fetch is unavailable.
Version History
VersionChangesv13.0.0generateStaticParams introduced.
revalidatePathrevalidatePath allows you to revalidate data associated with a specific path. This is useful for scenarios where you want to update your cached data without waiting for a revalidation period to expire.
app/api/revalidate/route.ts import { NextRequest, NextResponse } from 'next/server'
import { revalidatePath } from 'next/cache'
 
export async function GET(request: NextRequest) {
  const path = request.nextUrl.searchParams.get('path') || '/'
  revalidatePath(path)
  return NextResponse.json({ revalidated: true, now: Date.now() })
}
Good to know:
revalidatePath is available in both Node.js and Edge runtimes.
Good to know:
revalidatePath is available in both Node.js and Edge runtimes.
revalidatePath will revalidate all segments under a dynamic route segment. For example, if you have a dynamic segment /product/[id] and you call revalidatePath('/product/[id]'), then all segments under /product/[id] will be revalidated as requested.
revalidatePath only invalidates the cache when the path is next visited. This means calling revalidatePath with a dynamic route segment will not immediately trigger many revalidations at once. The invalidation only happens when the path is next visited.
Parameters
 revalidatePath(path: string): void;
path: A string representing the filesystem path associated with the data you want to revalidate. This is not the literal route segment (e.g. /product/123) but instead the path on the filesystem (e.g. /product/[id]).
Returns
Returns
revalidatePath does not return any value.
Examples
Node.js Runtime
app/api/revalidate/route.ts import { NextRequest, NextResponse } from 'next/server'
import { revalidatePath } from 'next/cache'
 
export async function GET(request: NextRequest) {
  const path = request.nextUrl.searchParams.get('path') || '/'
  revalidatePath(path)
  return NextResponse.json({ revalidated: true, now: Date.now() })
}
Edge Runtime
app/api/revalidate/route.ts import { NextRequest, NextResponse } from 'next/server'
import { revalidatePath } from 'next/cache'
 
export const runtime = 'edge'
 
export async function GET(request: NextRequest) {
  const path = request.nextUrl.searchParams.get('path') || '/'
  revalidatePath(path)
revalidatePath(path)
  return NextResponse.json({ revalidated: true, now: Date.now() })
}
useRouterThe useRouter hook allows you to programmatically change routes inside Client Components.
Recommendation: Use the <Link> component for navigation unless you have a specific requirement for using useRouter.
app/example-client-component.tsx 'use client'
 
import { useRouter } from 'next/navigation'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}
useRouter()
router.push(href: string): Perform a client-side navigation to the provided route. Adds a new entry into the browser’s history stack.
router.replace(href: string): Perform a client-side navigation to the provided route without adding a new entry into the browser’s history stack.
router.refresh(): Refresh the current route. Making a new request to the server, re-fetching data requests, and re-rendering Server Components. The client will merge the updated React Server Component payload without losing unaffected client-side React (e.g. useState) or browser state (e.g. scroll position).
router.prefetch(href: string): Prefetch the provided route for faster client-side transitions.
router.back(): Navigate back to the previous route in the browser’s history stack using soft navigation.
router.forward(): Navigate forwards to the next page in the browser’s history stack using soft navigation.
Good to know:
The push() and replace() methods will perform a soft navigation if the new route has been prefetched, and either, doesn't include dynamic segments or has the same dynamic parameters as the current route.
next/link automatically prefetch routes as they become visible in the viewport.
next/link automatically prefetch routes as they become visible in the viewport.
refresh() could re-produce the same result if fetch requests are cached. Other dynamic functions like cookies and headers could also change the response.
Migrating from the pages directory:
The new useRouter hook should be imported from next/navigation and not next/router
The pathname string has been removed and is replaced by usePathname()
The query object has been removed and is replaced by useSearchParams()
router.events is not currently supported. See below.
View the full migration guide.
Examples
Router Events
You can listen for page changes by composing other Client Component hooks like usePathname and useSearchParams.
app/components/navigation-events.js 'use client'
 
import { useEffect } from 'react'
import { usePathname, useSearchParams } from 'next/navigation'
 
export function NavigationEvents() {
  const pathname = usePathname()
export function NavigationEvents() {
  const pathname = usePathname()
  const searchParams = useSearchParams()
 
  useEffect(() => {
    const url = `${pathname}?${searchParams}`
    console.log(url)
    // You can now use the current URL
    // ...
  }, [pathname, searchParams])
 
  return null
}
Which can be imported into a layout.
app/layout.js import { Suspense } from 'react'
import { NavigationEvents } from './components/navigation-events'
 
export default function Layout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
 
        <Suspense fallback={null}>
          <NavigationEvents />
        </Suspense>
      </body>
    </html>
  )
}
</body>
    </html>
  )
}
Good to know: <NavigationEvents> is wrapped in a Suspense boundary becauseuseSearchParams() causes client-side rendering up to the closest Suspense boundary during static rendering. Learn more.
VersionChangesv13.0.0useRouter from next/navigation introduced.
useSelectedLayoutSegmentuseSelectedLayoutSegment is a Client Component hook that lets you read the active route segment one level below the Layout it is called from.
It is useful for navigation UI, such as tabs inside a parent layout that change style depending on the active child segment.
app/example-client-component.tsx 'use client'
 
import { useSelectedLayoutSegment } from 'next/navigation'
 
export default function ExampleClientComponent() {
  const segment = useSelectedLayoutSegment()
 
  return <p>Active segment: {segment}</p>
}
Good to know:
Since useSelectedLayoutSegment is a Client Component hook, and Layouts are Server Components by default, useSelectedLayoutSegment is usually called via a Client Component that is imported into a Layout.
useSelectedLayoutSegment only returns the segment one level down. To return all active segments, see useSelectedLayoutSegments
Parameters
 const segment = useSelectedLayoutSegment()
Parameters
 const segment = useSelectedLayoutSegment()
useSelectedLayoutSegment does not take any parameters.
Returns
useSelectedLayoutSegment returns a string of the active segment or null if one doesn't exist.
For example, given the Layouts and URLs below, the returned segment would be:
LayoutVisited URLReturned Segmentapp/layout.js/nullapp/layout.js/dashboard'dashboard'app/dashboard/layout.js/dashboardnullapp/dashboard/layout.js/dashboard/settings'settings'app/dashboard/layout.js/dashboard/analytics'analytics'app/dashboard/layout.js/dashboard/analytics/monthly'analytics'
Examples
Creating an active link component
You can use useSelectedLayoutSegment to create an active link component that changes style depending on the active segment. For example, a featured posts list in the sidebar of a blog:
app/blog/blog-nav-link.tsx 'use client'
 
import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
import { useSelectedLayoutSegment } from 'next/navigation'
 
// This *client* component will be imported into a blog layout
export default function BlogNavLink({
  slug,
  children,
}: {
  slug: string
  children: React.ReactNode
}) {
  // Navigating to `/blog/hello-world` will return 'hello-world'
  // for the selected layout segment
  const segment = useSelectedLayoutSegment()
  const isActive = slug === segment
 
  return (
    <Link
      href={`/blog/${slug}`}
      // Change style depending on whether the link is active
      style={{ fontWeight: isActive ? 'bold' : 'normal' }}
    >
      {children}
    </Link>
  )
}
app/blog/layout.tsx // Import the Client Component into a parent Layout (Server Component)
app/blog/layout.tsx // Import the Client Component into a parent Layout (Server Component)
import { BlogNavLink } from './blog-nav-link'
import getFeaturedPosts from './get-featured-posts'
 
export default async function Layout({
  children,
}: {
  children: React.ReactNode
}) {
  const featuredPosts = await getFeaturedPosts()
  return (
    <div>
      {featuredPosts.map((post) => (
        <div key={post.id}>
          <BlogNavLink slug={post.slug}>{post.title}</BlogNavLink>
        </div>
      ))}
      <div>{children}</div>
    </div>
  )
}
Version History
VersionChangesv13.0.0useSelectedLayoutSegment introduced.
useParamsuseParams is a Client Component hook that lets you read a route's dynamic params filled in by the current URL.
app/example-client-component.tsx 'use client'
 
import { useParams } from 'next/navigation'
 
export default function ExampleClientComponent() {
  const params = useParams()
 
  // Route -> /shop/[tag]/[item]
  // URL -> /shop/shoes/nike-air-max-97
  // `params` -> { tag: 'shoes', item: 'nike-air-max-97' }
  console.log(params)
 
  return <></>
}
Parameters
 const params = useParams()
useParams does not take any parameters.
Returns
useParams returns an object containing the current route's filled in dynamic parameters.
Each property in the object is an active dynamic segment.
Each property in the object is an active dynamic segment.
The properties name is the segment's name, and the properties value is what the segment is filled in with.
The properties value will either be a string or array of string's depending on the type of dynamic segment.
If the route contains no dynamic parameters, useParams returns an empty object.
If used in pages, useParams will return null.
For example:
RouteURLuseParams()app/shop/page.js/shopnullapp/shop/[slug]/page.js/shop/1{ slug: '1' }app/shop/[tag]/[item]/page.js/shop/1/2{ tag: '1', item: '2' }app/shop/[...slug]/page.js/shop/1/2{ slug: ['1', '2'] }
Version History
VersionChangesv13.3.0useParams introduced.
usePathnameusePathname is a Client Component hook that lets you read the current URL's pathname.
app/example-client-component.tsx 'use client'
 
import { usePathname } from 'next/navigation'
 
export default function ExampleClientComponent() {
  const pathname = usePathname()
  return <p>Current pathname: {pathname}</p>
}
usePathname intentionally requires using a Client Component. It's important to note Client Components are not a de-optimization. They are an integral part of the Server Components architecture.
For example, a Client Component with usePathname will be rendered into HTML on the initial page load. When navigating to a new route, this component does not need to be re-fetched. Instead, the component is downloaded once (in the client JavaScript bundle), and re-renders based on the current state.
Good to know:
Good to know:
Reading the current URL from a Server Component is not supported. This design is intentional to support layout state being preserved across page navigations.
Compatibility mode:
usePathname can return null when a fallback route is being rendered or when a pages directory page has been automatically statically optimized by Next.js and the router is not ready.
Next.js will automatically update your types if it detects both an app and pages directory in your project.
Parameters
 const pathname = usePathname()
usePathname does not take any parameters.
Returns
usePathname returns a string of the current URL's pathname. For example:
URLReturned value/'/'/dashboard'/dashboard'/dashboard?v=2'/dashboard'/blog/hello-world'/blog/hello-world'
Examples
Do something in response to a route change
app/example-client-component.tsx 'use client'
 
import { usePathname, useSearchParams } from 'next/navigation'
import { usePathname, useSearchParams } from 'next/navigation'
 
function ExampleClientComponent() {
  const pathname = usePathname()
  const searchParams = useSearchParams()
  useEffect(() => {
    // Do something here...
  }, [pathname, searchParams])
}
VersionChangesv13.0.0usePathname introduced.
generateImageMetadataYou can use generateImageMetadata to generate different versions of one image or return multiple images for one route segment. This is useful for when you want to avoid hard-coding metadata values, such as for icons.
Parameters
generateImageMetadata function accepts the following parameters:
params (optional)
An object containing the dynamic route parameters object from the root segment down to the segment generateImageMetadata is called from.
icon.tsx export function generateImageMetadata({
  params,
}: {
  params: { slug: string }
}) {
  // ...
}
RouteURLparamsapp/shop/icon.js/shopundefinedapp/shop/[slug]/icon.js/shop/1{ slug: '1' }app/shop/[tag]/[item]/icon.js/shop/1/2{ tag: '1', item: '2' }app/shop/[...slug]/icon.js/shop/1/2{ slug: ['1', '2'] }
Returns
Returns
The generateImageMetadata function should return an array of objects containing the image's metadata such as alt and size. In addition, each item must include an id value will be passed to the props of the image generating function.
Image Metadata ObjectTypeidstring (required)altstringsize{ width: number; height: number }contentTypestring
icon.tsx import { ImageResponse } from 'next/server'
 
export function generateImageMetadata() {
  return [
    {
      contentType: 'image/png',
      size: { width: 48, height: 48 },
      id: 'small',
    },
    {
      contentType: 'image/png',
      size: { width: 72, height: 72 },
      id: 'medium',
    },
  ]
}
 
export default function Icon({ id }: { id: string }) {
  return new ImageResponse(
return new ImageResponse(
    (
      <div
        style={{
          width: '100%',
          height: '100%',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          fontSize: 88,
          background: '#000',
          color: '#fafafa',
        }}
      >
        Icon {id}
      </div>
    )
  )
}
Examples
Using external data
This example uses the params object and external data to generate multiple Open Graph images for a route segment.
app/products/[id]/opengraph-image.tsx import { ImageResponse } from 'next/server'
import { getCaptionForImage, getOGImages } from '@/app/utils/images'
 
export async function generateImageMetadata({
  params,
}: {
  params: { id: string }
}) {
params,
}: {
  params: { id: string }
}) {
  const images = await getOGImages(params.id)
 
  return images.map((image, idx) => ({
    id: idx,
    size: { width: 1200, height: 600 },
    alt: image.text,
    contentType: 'image/png',
  }))
}
 
export default async function Image({
  params,
  id,
}: {
  params: { id: string }
  id: number
}) {
  const productId = params.id
  const imageId = id
  const text = await getCaptionForImage(productId, imageId)
 
  return new ImageResponse(
    (
      <div
        style={
          {
            // ...
          }
        }
      >
        {text}
      </div>
}
        }
      >
        {text}
      </div>
    )
  )
}
Version History
VersionChangesv13.3.0generateImageMetadata introduced.
draftModeThe draftMode function allows you to detect Draft Mode inside a Server Component.
app/page.js import { draftMode } from 'next/headers'
 
export default function Page() {
  const { isEnabled } = draftMode()
  return (
    <main>
      <h1>My Blog Post</h1>
      <p>Draft Mode is currently {isEnabled ? 'Enabled' : 'Disabled'}</p>
    </main>
  )
}
Version History
VersionChangesv13.4.0draftMode introduced.
useSearchParamsuseSearchParams is a Client Component hook that lets you read the current URL's query string.
useSearchParams returns a read-only version of the URLSearchParams interface.
app/dashboard/search-bar.tsx 'use client'
 
import { useSearchParams } from 'next/navigation'
 
export default function SearchBar() {
  const searchParams = useSearchParams()
 
  const search = searchParams.get('search')
 
  // URL -> `/dashboard?search=my-project`
  // `search` -> 'my-project'
  return <>Search: {search}</>
}
Parameters
 const searchParams = useSearchParams()
useSearchParams does not take any parameters.
Returns
useSearchParams returns a read-only version of the URLSearchParams interface, which includes utility methods for reading the URL's query string:
URLSearchParams.get(): Returns the first value associated with the search parameter. For example:
URLSearchParams.get(): Returns the first value associated with the search parameter. For example:
URLsearchParams.get("a")/dashboard?a=1'1'/dashboard?a=''/dashboard?b=3null/dashboard?a=1&a=2'1' - use getAll() to get all values
URLSearchParams.has(): Returns a boolean value indicating if the given parameter exists. For example:
URLsearchParams.has("a")/dashboard?a=1true/dashboard?b=3false
Learn more about other read-only methods of URLSearchParams, including the getAll(), keys(), values(), entries(), forEach(), and toString().
Good to know:
useSearchParams is a Client Component hook and is not supported in Server Components to prevent stale values during partial rendering.
If an application includes the /pages directory, useSearchParams will return ReadonlyURLSearchParams | null. The null value is for compatibility during migration since search params cannot be known during pre-rendering of a page that doesn't use getServerSideProps
Behavior
Static Rendering
If a route is statically rendered, calling useSearchParams() will cause the tree up to the closest Suspense boundary to be client-side rendered.
This allows a part of the page to be statically rendered while the dynamic part that uses searchParams is client-side rendered.
You can reduce the portion of the route that is client-side rendered by wrapping the component that uses useSearchParams in a Suspense boundary. For example:
app/dashboard/search-bar.tsx 'use client'
 
import { useSearchParams } from 'next/navigation'
 
export default function SearchBar() {
  const searchParams = useSearchParams()
 
  const search = searchParams.get('search')