Metadata

Note: Built-in support for SEO through metadata, introduced in 13.2, replaces the previous head.js implementation. The head.js special file was deprecated in 13.2 and removed in a future version. View migration guide.

Metadata can be used in any page.js or layout.js Server Component. This API reference includes every possible option for the returned metadata object.

// Static metadata
export const metadata = {
  title: '...',
};

// or dynamic metadata
export async function generateMetadata({ params, searchParams }) {
  return { title: '...' };
}

Both static and dynamic metadata through generateMetadata are only supported in Server Components.

Ordering

Each metadata or generateMetadata export defined in the layout/page path will be evaluated in order starting from the highest level, and ending with the export closest to the page.

For example:

  1. app/layout.tsx (Root Layout)
  2. app/page/blog/layout.tsx (Blog Layout)
  3. app/page/blog/[slug]/page.tsx (Blog Page)

Objects are shallow merged together to form the final metadata output. Duplicate keys are replaced based on their ordering. Learn more about pages and layouts.

generateMetadata

You can use generateMetadata to fetch metadata that requires dynamic values. Similar to page, generateMetadata has access to the params and searchParams props.

app/products/[id]/page.tsx
export async function generateMetadata({
  params,
  searchParams,
}: {
  params: { id: string },
  searchParams: { [key: string]: string | string[] | undefined };
}) {
  // For /products/123, params.id is "123"
  // For /products/123?color=black, searchParams.color is "black"
  // The return value is the metadata object
  return { title: '...' };
}

When fetching data, the fetch response is cached and reused between both generateMetadata and the Page Server Component below, resulting in a single fetch request. If you cannot use fetch directly, you can use cache. Learn more.

app/products/[id]/page.tsx
import type { Metadata } from 'next'

async function getProduct(id) {
  const res = await fetch(`https://.../api/products/${id}`);
  return res.json();
}

export async function generateMetadata({ params }): Promise<Metadata> {
  const product = await getProduct(params.id);
  return { title: product.title }
}

export default async function Page({ params }) {
  const product = await getProduct(params.id);
  // ...
}

The following Next.js methods can also be used inside generateMetadata:

Default Metadata

There are two default meta tags:

  • The meta charset tag sets the character encoding for the website.
  • The meta viewport tag sets the viewport width and scale for the website to adjust for different devices.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

These are always added even if a route doesn't define metadata.

Optional Metadata

title

export const metadata = {
  title: 'Next.js',
};
Output

<title>Next.js</title>

Title Templates

You can use a template to add a prefix or suffix to the title of a page. Any layout can add the title template, including deeper nested layouts.

app/layout.tsx
export const metadata = {
  title: {
    default: 'Acme',
    template: '%s | Acme',
  },
}
app/page.tsx
// Output: <title>Acme</title>
export const metadata = {
  // Default title is used from the layout
  description: 'ACME is a...',
}
app/about/page.tsx
// Output: <title>About | Acme</title>
export const metadata = {
  title: 'About',
}

description

export const metadata = {
  description: 'The React Framework for the Web',
};
Output

<meta name="description" content="The React Framework for the Web">

Basic Options

export const metadata = {
  generator: 'Next.js',
  applicationName: 'Next.js',
  referrer: 'origin-when-cross-origin',
  keywords: ['Next.js', 'React', 'JavaScript'],
  authors: [{ name: 'Seb' }, { name: 'Josh', url: 'https://nextjs.org' }],
  colorScheme: 'dark',
  creator: 'Jiachi Liu',
  publisher: 'Sebastian Markbåge',
  alternates: {},
  formatDetection: {
    email: false,
    address: false,
    telephone: false,
  },
};
Output
<meta name="application-name" content="Next.js">
<meta name="author" content="Seb"/>
<link rel="author" href="https://nextjs.org"/>
<meta name="author" content="Josh"/>
<meta name="generator" content="Next.js">
<meta name="keywords" content="Next.js,React,JavaScript">
<meta name="referrer" content="origin-when-cross-origin">
<meta name="color-scheme" content="dark">
<meta name="creator" content="Jiachi Liu">
<meta name="publisher" content="Sebastian Markbåge">
<meta name="format-detection" content="telephone=no, address=no, email=no">

openGraph

export const metadata = {
  openGraph: {
    title: 'Next.js',
    description: 'The React Framework for the Web',
    url: 'https://nextjs.org',
    siteName: 'Next.js',
    images: [
      {
        url: 'https://nextjs.org/og.png',
        width: 800,
        height: 600,
      },
      {
        url: 'https://nextjs.org/og-alt.png',
        width: 1800,
        height: 1600,
        alt: 'My custom alt',
      },
    ],
    locale: 'en-US',
    type: 'website',
  },
};
Output
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:url" content="https://nextjs.org/" />
<meta property="og:site_name" content="Next.js" />
<meta property="og:locale" content="en-US" />
<meta property="og:image:url" content="https://nextjs.org/og.png" />
<meta property="og:image:width" content="800" />
<meta property="og:image:height" content="600" />
<meta property="og:image:url" content="https://nextjs.org/og-alt.png" />
<meta property="og:image:width" content="1800" />
<meta property="og:image:height" content="1600" />
<meta property="og:image:alt" content="My custom alt" />
<meta property="og:type" content="website" />
export const metadata = {
  openGraph: {
    title: 'Next.js',
    description: 'The React Framework for the Web',
    type: 'article',
    publishedTime: '2023-01-01T00:00:00.000Z',
    authors: ['Seb', 'Josh'],
  },
};
Output
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2023-01-01T00:00:00.000Z" />
<meta property="article:author" content="Seb" />
<meta property="article:author" content="Josh" />

robots

export const metadata = {
  robots: {
    index: false,
    follow: true,
    nocache: true,
    googleBot: {
      index: true,
      follow: false,
      noimageindex: true,
      'max-video-preview': -1,
      'max-image-preview': 'large',
      'max-snippet': -1,
    },
  },
};
Output
<meta name="robots" content="noindex, follow, nocache" />
<meta
  name="googlebot"
  content="index, nofollow, noimageindex, max-video-preview:-1, max-image-preview:large, max-snippet:-1"
/>

icons

Next.js has built-in support for favicon detection. If you place a favicon.ico file in the app/ directory, it will automatically add the correct link tags to your page.

You do not need to manually add the icon key below, however, it is still supported in case your favicon is not stored inside the directory.

export const metadata = {
  icons: {
    icon: '/icon.png',
    shortcut: '/shortcut-icon.png',
    apple: '/apple-icon.png',
    other: {
      rel: 'apple-touch-icon-precomposed',
      url: '/apple-touch-icon-precomposed.png',
    },
  },
};
Output
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
  rel="apple-touch-icon-precomposed"
  href="/apple-touch-icon-precomposed.png"
/>
export const metadata = {
  icons: {
    icon: [{ url: '/icon.png' }, new URL('/icon.png', 'https://example.com')],
    shortcut: ['/shortcut-icon.png'],
    apple: [
      { url: '/apple-icon.png' },
      { url: '/apple-icon-x3.png', sizes: '180x180', type: 'image/png' },
    ],
    other: [
      {
        rel: 'apple-touch-icon-precomposed',
        url: '/apple-touch-icon-precomposed.png',
      },
    ],
  },
};
Output
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
  rel="apple-touch-icon-precomposed"
  href="/apple-touch-icon-precomposed.png"
/>
<link rel="icon" href="https://example.com/icon.png" />
<link
  rel="apple-touch-icon"
  href="/apple-icon-x3.png"
  sizes="180x180"
  type="image/png"
/>

Note: The msapplication-* meta tags are no longer supported in Chromium builds of Microsoft Edge, and thus no longer needed.

themeColor

Learn more about theme-color.

Simple theme color

export const metadata = {
  themeColor: 'black',
};
Output
<meta name="theme-color" content="black" />

With media attribute

export const metadata = {
  themeColor: [
    { media: '(prefers-color-scheme: light)', color: 'cyan' },
    { media: '(prefers-color-scheme: dark)', color: 'black' },
  ],
};
Output
<meta name="theme-color" media="(prefers-color-scheme: light)" content="cyan" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="black" />

manifest

The manifest.json file is the only file that every extension using WebExtension APIs must contain.

export const metadata = {
  manifest: 'https://nextjs.org/manifest.json',
};
Output
<link rel="manifest" href="https://nextjs.org/manifest.json" />

twitter

Learn more about the Twitter Card markup reference.

export const metadata = {
  twitter: {
    card: 'summary_large_image',
    title: 'Next.js',
    description: 'The React Framework for the Web',
    siteId: '1467726470533754880',
    creator: '@nextjs',
    creatorId: '1467726470533754880',
    images: ['https://nextjs.org/og.png'],
  },
};
Output
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
export const metadata = {
  twitter: {
    card: 'app',
    title: 'Next.js',
    description: 'The React Framework for the Web',
    siteId: '1467726470533754880',
    creator: '@nextjs',
    creatorId: '1467726470533754880',
    images: {
      url: 'https://nextjs.org/og.png',
      alt: 'Next.js Logo',
    },
    app: {
      name: 'twitter_app',
      id: {
        iphone: 'twitter_app://iphone',
        ipad: 'twitter_app://ipad',
        googleplay: 'twitter_app://googleplay',
      },
      url: {
        iphone: 'https://iphone_url',
        ipad: 'https://ipad_url',
      },
    },
  },
};
Output
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:card" content="app" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
<meta name="twitter:image:alt" content="Next.js Logo" />
<meta name="twitter:app:name:iphone" content="twitter_app" />
<meta name="twitter:app:id:iphone" content="twitter_app://iphone" />
<meta name="twitter:app:id:ipad" content="twitter_app://ipad" />
<meta name="twitter:app:id:googleplay" content="twitter_app://googleplay" />
<meta name="twitter:app:url:iphone" content="https://iphone_url" />
<meta name="twitter:app:url:ipad" content="https://ipad_url" />
<meta name="twitter:app:name:ipad" content="twitter_app" />
<meta name="twitter:app:name:googleplay" content="twitter_app" />

viewport

// Note: This is the same values as the default value set
// You likely don't need to change this, but it's included for completeness
export const metadata = {
  viewport: {
    width: 'device-width',
    initialScale: 1,
    maximumScale: 1,
  },
};
Output

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

verification

export const metadata = {
  verification: {
    google: 'google',
    yandex: 'yandex',
    yahoo: 'yahoo',
    other: {
      me: ['my-email', 'my-link'],
    },
  },
};
Output
<meta name="google-site-verification" content="google">
<meta name="y_key" content="yahoo">
<meta name="yandex-verification" content="yandex">
<meta name="me" content="my-email">
<meta name="me" content="my-link">

appleWebApp

export const metadata = {
  itunes: {
    appId: 'myAppStoreID',
    appArgument: 'myAppArgument',
  },
  appleWebApp: {
    title: 'Apple Web App',
    statusBarStyle: 'black-translucent',
    startupImage: [
      '/assets/startup/apple-touch-startup-image-768x1004.png',
      {
        url: '/assets/startup/apple-touch-startup-image-1536x2008.png',
        media: '(device-width: 768px) and (device-height: 1024px)',
      },
    ],
  },
};
Output
<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-argument=myAppArgument">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="Apple Web App">
<link href="/assets/startup/apple-touch-startup-image-768x1004.png" rel="apple-touch-startup-image">
<link href="/assets/startup/apple-touch-startup-image-1536x2008.png" media="(device-width: 768px) and (device-height: 1024px)" rel="apple-touch-startup-image">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

alternates

export const metadata = {
  alternates: {
    canonical: 'https://nextjs.org',
    languages: {
      'en-US': 'https://nextjs.org/en-US',
      'de-DE': 'https://nextjs.org/de-DE',
    },
    media: {
      'only screen and (max-width: 600px)': 'https://nextjs.org/mobile',
    },
    types: {
      'application/rss+xml': 'https://nextjs.org/rss',
    },
  },
};
Output
<link rel="canonical" href="https://nextjs.org">
<link rel="alternate" hreflang="en-US" href="https://nextjs.org/en-US">
<link rel="alternate" hreflang="de-DE" href="https://nextjs.org/de-DE">
<link rel="alternate" media="only screen and (max-width: 600px)" href="https://nextjs.org/mobile">
<link rel="alternate" type="application/rss+xml" href="https://nextjs.org/rss">
export const metadata = {
  appLinks: {
    ios: {
      url: 'https://nextjs.org/ios',
      app_store_id: 'app_store_id',
    },
    android: {
      package: 'com.example.android/package',
      app_name: 'app_name_android',
    },
    web: {
      url: 'https://nextjs.org/web',
      should_fallback: true,
    },
  },
};
Output
<meta property="al:ios:url" content="https://nextjs.org/ios">
<meta property="al:ios:app_store_id" content="app_store_id">
<meta property="al:android:package" content="com.example.android/package">
<meta property="al:android:app_name" content="app_name_android">
<meta property="al:web:url" content="https://nextjs.org/web">
<meta property="al:web:should_fallback" content="true">

archives

Describes a collection of records, documents, or other materials of historical interest (source).

export const metadata = {
  archives: ['https://nextjs.org/13'],
};
Output
<link rel="archives" href="https://nextjs.org/13">

assets

export const metadata = {
  assets: ['https://nextjs.org/assets'],
};
Output
<link rel="assets" href="https://nextjs.org/assets">

bookmarks

export const metadata = {
  bookmarks: ['https://nextjs.org/13'],
};
Output
<link rel="bookmarks" href="https://nextjs.org/13">

category

export const metadata = {
  category: 'technology',
};
Output
<meta name="category" content="technology">

other

All metadata options should be covered using the built-in support. However, there may be custom metadata tags specific to your site, or brand new metadata tags just released. You can use the other option to render any custom metadata tag.

export const metadata = {
  other: {
    custom: 'meta',
  },
};
Output
<meta name="custom" content="meta">

Unsupported Metadata

The following metadata types do not currently have built-in support. However, they can still be rendered in the layout or page itself.

MetadataRecommendation
<meta http-equiv="...">Render the tag in the layout or page itself.
<meta charset="...">Render the tag in the layout or page itself.
<base>Render the tag in the layout or page itself.
<noscript>Render the tag in the layout or page itself.
<style>Learn more about styling in Next.js.
<script>Learn more about using scripts.
<link rel="stylesheet" />import stylesheets directly in the layout or page itself.
<link rel="preload />Learn more about using scripts.
<link rel="preconnect" />Learn more about using scripts.

Types

You can add type safety to your metadata by using the Metadata type. If you are using the built-in TypeScript plugin in your IDE, you do not need to manually add the type, but you can still explicitly add it if you want.

import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'Next.js',
};

For JavaScript projects, you can use JSDoc to add type safety.

/** @type {import("next").Metadata} */
export const metadata = {
  title: 'Hi',
};

Next Steps