Skip to main content
The Metadata APIs define your application’s <head> tags for SEO, social sharing, and browser behavior. Next.js automatically generates the relevant HTML from the metadata you export.
The metadata export and generateMetadata function are only supported in Server Components (layouts and pages).

Default fields

Two <meta> tags are always added by Next.js, even when no metadata is defined:
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

Static metadata

Export a metadata object from a layout.tsx or page.tsx file:
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'My Blog',
  description: 'Read about the latest topics.',
}

export default function Layout({ children }: { children: React.ReactNode }) {
  return <>{children}</>
}

Dynamic metadata

Use generateMetadata to fetch metadata that depends on route parameters or external data:
import type { Metadata, ResolvingMetadata } from 'next'

type Props = {
  params: Promise<{ slug: string }>
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}

export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const slug = (await params).slug

  const post = await fetch(`https://api.example.com/blog/${slug}`).then(
    (res) => res.json()
  )

  return {
    title: post.title,
    description: post.description,
  }
}

export default function Page({ params, searchParams }: Props) {
  return <div />
}

Avoiding duplicate data fetches

When the same data is needed in both generateMetadata and the page component, use React’s cache to deduplicate the request:
import { cache } from 'react'

export const getPost = cache(async (slug: string) => {
  const res = await fetch(`https://api.example.com/blog/${slug}`)
  return res.json()
})

Metadata fields

The Metadata object supports the following commonly used fields:
title
string | object
The page title. Can be a plain string, or an object with default, template, and absolute for title inheritance across layouts.
title: 'My Page'
// or
title: {
  template: '%s | My Site',
  default: 'My Site',
}
description
string
Page description used by search engines.
description: 'A page about Next.js metadata.'
keywords
string | string[]
Keywords for the page.
keywords: ['Next.js', 'React', 'metadata']
authors
object[]
Page authors.
authors: [{ name: 'Jane Doe', url: 'https://example.com' }]
alternates
object
Canonical and alternate URLs.
alternates: {
  canonical: 'https://example.com/page',
  languages: {
    'en-US': 'https://example.com/en/page',
  },
}
Used by social platforms (Facebook, LinkedIn, Slack) to generate link previews.
openGraph: {
  title: 'My Page',
  description: 'A page description.',
  url: 'https://example.com/page',
  siteName: 'My Site',
  images: [
    {
      url: 'https://example.com/og.png',
      width: 1200,
      height: 630,
      alt: 'Preview of My Page',
    },
  ],
  type: 'website',
}
Controls how your page appears when shared on X (formerly Twitter).
twitter: {
  card: 'summary_large_image',
  title: 'My Page',
  description: 'A page description.',
  creator: '@username',
  images: ['https://example.com/og.png'],
}
Instructs search engine crawlers.
robots: {
  index: true,
  follow: true,
  googleBot: {
    index: true,
    follow: true,
    'max-image-preview': 'large',
  },
}
Define favicons and Apple touch icons.
icons: {
  icon: '/favicon.ico',
  apple: '/apple-touch-icon.png',
  shortcut: '/shortcut-icon.png',
}

File-based metadata

Next.js supports special file conventions that generate metadata automatically:
FilePurpose
favicon.icoBrowser tab icon
icon.png / icon.svgApp icon
apple-icon.pngApple touch icon
opengraph-image.jpgOG image for social sharing
twitter-image.jpgTwitter card image
robots.txtSearch crawler instructions
sitemap.xmlSite URL map for crawlers
Place these files in the app directory (or in a route segment folder for route-specific metadata).

Generated Open Graph images

Use the ImageResponse constructor from next/og to generate dynamic OG images using JSX:
import { ImageResponse } from 'next/og'
import { getPost } from '@/app/lib/data'

export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'

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

  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 128,
          background: 'white',
          width: '100%',
          height: '100%',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        {post.title}
      </div>
    )
  )
}
ImageResponse supports flexbox and a subset of CSS properties. Advanced layouts using display: grid are not supported. Test your OG images at the Vercel OG Playground.

Streaming metadata

For dynamically rendered pages, Next.js streams metadata separately from page content, injecting it into <head> once generateMetadata resolves. This means visual content can start streaming before metadata is ready. Streaming metadata is disabled for known bots and crawlers (e.g. Twitterbot, Bingbot) that expect metadata to be in the initial HTML. You can customize this behavior with the htmlLimitedBots config option.

Build docs developers (and LLMs) love