GʀᴜᴍᴘʏCᴀᴛ
GʀᴜᴍᴘʏCᴀᴛ

Reputation: 8972

Why is my dynamic metadata generation not working in Next 14?

Working on my first Next.js 14 site I've read through the documentation for Dynamic Metadata but for some reason when I run my site locally and visit the page the metadata does not generate.

Structure:

[slug]/page.tsx

page.tsx

import type {Metadata} from 'next'

// API
import {getPage} from '@/api/page'

type MetadataProps = {
  title: string
  description: string
}

export async function generateMetadata(params: MetadataProps): Promise<Metadata> {
  console.log(params)
  return {
    title: {
      template: `%s | ${params?.title}`,
      default: params?.title,
    },
    description: params?.description,
  }
}

export default async function Page({params}: Readonly<{params: {slug: string}}>) {
  const page = await getPage(params?.slug)
  console.log({page})

  await generateMetadata({
    title: page?.title,
    description: page?.description,

  })

  return (
    <div>
      <p>Page: {params?.slug}</p>
    </div>
  )
}

but in the console log before generateMetadata and after I get data from the API getPage I see:

{
  page: {
    description: 'description',
    title: 'Test page',
    _createdAt: '2024-08-05T18:38:16Z',
    _id: 'some id',
    _updatedAt: '2024-08-14T14:17:45Z',
    slug: 'test-page'
  }
}

along with seeing the object correctly in params:

{
  title: 'Test page',
  description: 'description',
}

What is the correct way to dynamically generate metadata in Next.js 14 based on the API call an why do I not see the metadata?

Upvotes: 0

Views: 252

Answers (1)

Moshe Fortgang
Moshe Fortgang

Reputation: 1150

You should call the API from the generateMetadata function instead of from the Page function.

Here's an example of how the code should look:

import type {Metadata} from 'next'

// API
import {getPage} from '@/api/page'


type Props = {
  params: { slug: string }
}

export async function generateMetadata(
  { params }: Props,
): Promise<Metadata> {

  // read route params
  const slug = params.slug

  const page = await getPage(slug)

  return {
    title: {
      template: `%s | ${page?.title}`,
      default: page?.title,
    },
    description: page?.description,
  }
}

export default async function Page({params}: Readonly<{params: {slug: string}}>) {
  return (
    <div>
      <p>Page: {params?.slug}</p>
    </div>
  )
}

For more details, refer to the official Next.js documentation on the generateMetadata function here.

Upvotes: 0

Related Questions