Search code examples
next.jsnext.js13next.js14

Next.js static and dynamic metadata not working


I'm checking this document to add either static or dynamic metadata to my page. When I run the page in localhost I can't see the metadata in the head. If I add it directly using <meta> everything works as intended.

The sample code when trying to use it directly in index.js is:

import Layout from "@/components/layout"

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
}

export default function Home() {
  return (
    <Layout>
      <div>This is an example</div>
    </Layout>
  )
}

Another issue I noticed is that if I tried to add the metadata in the layout.js file then I get the following error even though I'm not using the "use client" directive.

You are attempting to export "metadata" from a component marked with "use client",
which is disallowed. Either remove the export, or the "use client" directive. Read
more: https://nextjs.org/docs/getting-started/react-essentials#the-use-client-directive

This is the layout.js code:

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
}

export default function Layout({ children }) {
  return (
    <div>
      <p>This is a layout</p>
      {children}
    </div>
  )
}

The doc also mentions the following:

Config-based Metadata: Export a static metadata object or a dynamic generateMetadata
function in a layout.js or page.js file.

What constitutes a layout file? Is it any file called layout.js? Is it dependant on its parent directory same as pages?

You can find a sample of the project here


Solution

  • The sample repository you've provided is running Next.js 14 and is using the Page router methodology. Ideally, you should be using the App router methodology and I think this is where your problems are coming in. If I recall correctly, the Page router methodology components are client by default and you're attempting to use App router (server side components by default) functionality.

    In the App router, there are special files to be used and in this case they would be:

    • layout.tsx - the page at this level and its descendants will automatically use this layout.
    • page.tsx - uses the layout from layout.tsx at the same level. You don't need to import and use the component defined in layout.tsx.

    Here's an example structure, in TypeScript, of the App router:

    - app
      - layout.tsx
      - page.tsx
      - child-1
         - layout.tsx
         - page.tsx
      - child-2
         - page.tsx
    
    • / (app/page.tsx) - will show the content of page.tsx inside layout.tsx.
    • /child-1 (app/child-1/page.tsx) - will show the content of page.tsx inside the layout.tsx at the same level and all of that will be nested inside the app/layout.tsx.
    • /child-2 (app/child-2/page.tsx) - will show the content of page.tsx inside the app/layout.tsx.

    This is quite an oversimplified answer and there's a lot more to read in the App router documentation. The tl;dr of it is you need to use the App router instead of the Pages router for metadata functionality you've mentioned.