NextjsgenerateMetadata Function

generateMetadata Function

The static metadata object works when a page's title and description are known ahead of time. When they aren't — a blog post whose title comes from a CMS, a product page whose description comes from a database — export an async generateMetadata function instead. It receives the same params and searchParams as the page itself, so it can fetch exactly the data it needs to build the metadata object.
Signature

Function signature

TSX
import type { Metadata } from 'next'

export async function generateMetadata({
  params,
  searchParams,
}: {
  params: { slug: string }
  searchParams: { [key: string]: string | string[] | undefined }
}): Promise<Metadata> {
  // ...fetch data using params.slug...
  return {
    title: '...',
    description: '...',
  }
}
Worked example: a blog post

app/blog/[slug]/page.tsx

TSX
import type { Metadata } from 'next'
import { getPost } from '@/libs/posts'

export async function generateMetadata({
  params,
}: {
  params: { slug: string }
}): Promise<Metadata> {
  const post = await getPost(params.slug)

  if (!post) {
    return { title: 'Post not found' }
  }

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [post.coverImage],
      type: 'article',
      publishedTime: post.publishedAt,
    },
  }
}

export default async function BlogPostPage({
  params,
}: {
  params: { slug: string }
}) {
  const post = await getPost(params.slug)

  if (!post) return <p>Post not found</p>

  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  )
}
Note
Both generateMetadata and the page component call getPost(params.slug) here, but Next.js automatically memoizes identical fetch requests made during the same render pass. If getPost uses the built-in fetch (or you wrap it with React's cache()), the underlying data is only fetched once even though it's "called" from two different functions — you don't need to hand-roll caching to avoid the duplicate request.
This is a meaningful advantage over the older Pages Router pattern, where fetching the same data for both the head tags and the page body typically meant threading props through getServerSideProps manually.
Resolving relative to a parent
generateMetadata also receives a parent argument — a promise resolving to the metadata resolved by the nearest parent segment — which is useful when you want to extend rather than fully replace inherited fields.

Extending parent metadata

TSX
export async function generateMetadata(
  { params }: { params: { slug: string } },
  parent: ResolvingMetadata
) {
  const parentMetadata = await parent
  const post = await getPost(params.slug)

  return {
    ...parentMetadata,
    title: post.title,
  }
}
Tip
Reach for the static metadata object first — it's simpler and requires no data fetching. Switch to generateMetadata only once a page's metadata truly depends on params, searchParams, or an external data source.
  • generateMetadata is an async function that returns a Metadata object, used when metadata depends on runtime data.

  • It receives the same params and searchParams as the page component.

  • Next.js memoizes identical fetch calls within a render pass, so calling the same data function from both generateMetadata and the page doesn't duplicate the network request.

  • An optional parent argument resolves to the parent segment's metadata, useful for extending rather than replacing it.

  • Prefer the static metadata object when possible; use generateMetadata only when the values genuinely depend on fetched data.