generateMetadata

メタデータを定義するには、metadataオブジェクトまたはgenerateMetadata関数を使用できます。

metadataオブジェクト

静的メタデータを定義するには、layout.jsまたはpage.jsファイルからMetadataオブジェクトをエクスポートします。

import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: '...',
  description: '...',
}

export default function Page() {}

サポートされているオプションの完全なリストについては、メタデータフィールドを参照してください。

generateMetadata関数

動的な情報(現在のルートパラメータ、外部データ、または親セグメントのmetadataなど)に依存する動的メタデータは、Metadataオブジェクトを返すgenerateMetadata関数をエクスポートすることで設定できます。

import type { Metadata, ResolvingMetadata } from 'next'

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

export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  // ルートパラメータを読み取る
  const { id } = await params

  // データを取得
  const product = await fetch(`https://.../${id}`).then((res) => res.json())

  // オプションで親メタデータにアクセスして拡張(置換ではなく)
  const previousImages = (await parent).openGraph?.images || []

  return {
    title: product.title,
    openGraph: {
      images: ['/some-specific-page-image.jpg', ...previousImages],
    },
  }
}

export default function Page({ params, searchParams }: Props) {}

知っておくと便利:

  • メタデータはlayout.jspage.jsファイルに追加できます。
  • Next.jsは自動的にメタデータを解決し、ページに関連する<head>タグを作成します。
  • metadataオブジェクトとgenerateMetadata関数のエクスポートはサーバーコンポーネントでのみサポートされています。
  • 同じルートセグメントからmetadataオブジェクトとgenerateMetadata関数の両方をエクスポートすることはできません。
  • generateMetadata内のfetchリクエストは、generateMetadatagenerateStaticParams、レイアウト、ページ、サーバーコンポーネント間で同じデータに対して自動的にメモ化されます。
  • fetchが利用できない場合、Reactのcacheを使用できます
  • ファイルベースのメタデータは優先度が高く、metadataオブジェクトとgenerateMetadata関数を上書きします。

リファレンス

パラメータ

generateMetadata関数は以下のパラメータを受け取ります:

  • props - 現在のルートのパラメータを含むオブジェクト:

    • params - generateMetadataが呼び出されたセグメントまでの動的ルートパラメータオブジェクトを含むオブジェクト。例:

      ルートURLparams
      app/shop/[slug]/page.js/shop/1{ slug: '1' }
      app/shop/[tag]/[item]/page.js/shop/1/2{ tag: '1', item: '2' }
      app/shop/[...slug]/page.js/shop/1/2{ slug: ['1', '2'] }
    • searchParams - 現在のURLの検索パラメータを含むオブジェクト。例:

      URLsearchParams
      /shop?a=1{ a: '1' }
      /shop?a=1&b=2{ a: '1', b: '2' }
      /shop?a=1&a=2{ a: ['1', '2'] }
  • parent - 親ルートセグメントから解決されたメタデータのPromise。

戻り値

generateMetadataは、1つ以上のメタデータフィールドを含むMetadataオブジェクトを返す必要があります。

知っておくと便利:

  • メタデータがランタイム情報に依存しない場合は、generateMetadataではなく静的metadataオブジェクトを使用して定義する必要があります。
  • fetchリクエストは、generateMetadatagenerateStaticParams、レイアウト、ページ、サーバーコンポーネント間で同じデータに対して自動的にメモ化されます。fetchが利用できない場合、Reactのcacheを使用できます
  • searchParamspage.jsセグメントでのみ利用可能です。
  • Next.jsのredirect()およびnotFound()メソッドもgenerateMetadata内で使用できます。

メタデータフィールド

以下のフィールドがサポートされています:

title

title属性はドキュメントのタイトルを設定するために使用されます。文字列またはオプションのテンプレートオブジェクトとして定義できます。

文字列
layout.js | page.js
export const metadata = {
  title: 'Next.js',
}
<head> output
<title>Next.js</title>
default

title.defaultは、titleを定義していない子ルートセグメントにフォールバックタイトルを提供するために使用できます。

app/layout.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    default: 'Acme',
  },
}
app/about/page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {}

// 出力: <title>Acme</title>
template

title.templateは、ルートセグメントで定義されたtitlesにプレフィックスまたはサフィックスを追加するために使用できます。

import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    template: '%s | Acme',
    default: 'Acme', // テンプレート作成時にはdefaultが必要
  },
}

知っておくと便利:

  • title.templateルートセグメントに適用され、定義されたセグメント自体には適用されません。つまり:

    • title.templateを追加する場合、title.default必須です。
    • layout.jsで定義されたtitle.templateは、同じルートセグメントのpage.jsで定義されたtitleには適用されません。
    • page.jsで定義されたtitle.templateは効果がありません。ページは常に終端セグメントであるため(子ルートセグメントを持たない)。
  • ルートがtitleまたはtitle.defaultを定義していない場合、title.template効果がありません

absolute

title.absoluteは、親セグメントで設定されたtitle.template無視するタイトルを提供するために使用できます。

import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    template: '%s | Acme',
  },
}

知っておくと便利:

  • layout.js

    • title(文字列)とtitle.defaultは、独自のtitleを定義していない子セグメントのデフォルトタイトルを定義します。存在する場合、最も近い親セグメントのtitle.templateを拡張します。
    • title.absoluteは子セグメントのデフォルトタイトルを定義します。親セグメントのtitle.templateを無視します。
    • title.templateは子セグメントの新しいタイトルテンプレートを定義します。
  • page.js

    • ページが独自のタイトルを定義していない場合、最も近い親の解決済みタイトルが使用されます。
    • title(文字列)はルートのタイトルを定義します。存在する場合、最も近い親セグメントのtitle.templateを拡張します。
    • title.absoluteはルートタイトルを定義します。親セグメントのtitle.templateを無視します。
    • title.templatepage.jsでは効果がありません。ページは常にルートの終端セグメントであるため。

description

layout.js | page.js
export const metadata = {
  description: 'The React Framework for the Web',
}
<head> output
<meta name="description" content="The React Framework for the Web" />

その他のフィールド

layout.js | page.js
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' }],
  creator: 'Jiachi Liu',
  publisher: 'Sebastian Markbåge',
  formatDetection: {
    email: false,
    address: false,
    telephone: false,
  },
}
<head> 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" />

metadataBase

metadataBaseは、完全修飾URLを必要とするmetadataフィールドにベースURLプレフィックスを設定する便利なオプションです。

  • metadataBaseにより、現在のルートセグメント以下で定義されたURLベースのmetadataフィールドで、絶対URLではなく相対パスを使用できます。
  • フィールドの相対パスはmetadataBaseと組み合わされて完全修飾URLを形成します。
layout.js | page.js
export const metadata = {
  metadataBase: new URL('https://acme.com'),
  alternates: {
    canonical: '/',
    languages: {
      'en-US': '/en-US',
      'de-DE': '/de-DE',
    },
  },
  openGraph: {
    images: '/og-image.png',
  },
}
<head> output
<link rel="canonical" href="https://acme.com" />
<link rel="alternate" hreflang="en-US" href="https://acme.com/en-US" />
<link rel="alternate" hreflang="de-DE" href="https://acme.com/de-DE" />
<meta property="og:image" content="https://acme.com/og-image.png" />

知っておくと便利:

  • metadataBaseは通常、すべてのルートにわたるURLベースのmetadataフィールドに適用するためにルートapp/layout.jsで設定されます。
  • 絶対URLを必要とするすべてのURLベースのmetadataフィールドは、metadataBaseオプションで設定できます。
  • metadataBaseにはサブドメイン(例: https://app.acme.com)またはベースパス(例: https://acme.com/start/from/here)を含めることができます。
  • metadataフィールドが絶対URLを提供する場合、metadataBaseは無視されます。
  • metadataBaseを設定せずにURLベースのmetadataフィールドで相対パスを使用すると、ビルドエラーが発生します。
  • Next.jsは、metadataBase(例: https://acme.com/)と相対フィールド(例: /path)間の重複するスラッシュを単一のスラッシュ(例: https://acme.com/path)に正規化します。

URL構成

URL構成は、デフォルトのディレクトリトラバーサルセマンティクスよりも開発者の意図を優先します。

  • metadataBasemetadataフィールド間の末尾のスラッシュは正規化されます。
  • metadataフィールドの「絶対」パス(通常はURLパス全体を置き換える)は、「相対」パス(metadataBaseの末尾から開始)として扱われます。

例えば、以下のmetadataBaseがある場合:

import type { Metadata } from 'next'

export const metadata: Metadata = {
  metadataBase: new URL('https://acme.com'),
}

上記のmetadataBaseを継承し、独自の値を設定するmetadataフィールドは次のように解決されます:

metadataフィールド解決されたURL
/https://acme.com
./https://acme.com
paymentshttps://acme.com/payments
/paymentshttps://acme.com/payments
./paymentshttps://acme.com/payments
../paymentshttps://acme.com/payments
https://beta.acme.com/paymentshttps://beta.acme.com/payments

openGraph

layout.js | page.js
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', // 絶対URLである必要があります
        width: 800,
        height: 600,
      },
      {
        url: 'https://nextjs.org/og-alt.png', // 絶対URLである必要があります
        width: 1800,
        height: 1600,
        alt: 'カスタムaltテキスト',
      },
    ],
    videos: [
      {
        url: 'https://nextjs.org/video.mp4', // 絶対URLである必要があります
        width: 800,
        height: 600,
      },
    ],
    audio: [
      {
        url: 'https://nextjs.org/audio.mp3', // 絶対URLである必要があります
      },
    ],
    locale: 'en_US',
    type: 'website',
  },
}
<head> 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" content="https://nextjs.org/og.png" />
<meta property="og:image:width" content="800" />
<meta property="og:image:height" content="600" />
<meta property="og:image" 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="カスタムaltテキスト" />
<meta property="og:video" content="https://nextjs.org/video.mp4" />
<meta property="og:video:width" content="800" />
<meta property="og:video:height" content="600" />
<meta property="og:audio" content="https://nextjs.org/audio.mp3" />
<meta property="og:type" content="website" />
layout.js | page.js
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'],
  },
}
<head> 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" />

知っておくと便利:

  • Open Graph画像にはファイルベースのMetadata APIを使用すると便利です。設定エクスポートと実際のファイルを同期させる必要がなく、ファイルベースのAPIが自動的に正しいメタデータを生成します。

robots

layout.tsx | page.tsx
import type { Metadata } from 'next'

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

icons

知っておくと便利: アイコンには可能な限りファイルベースのMetadata APIを使用することを推奨します。設定エクスポートと実際のファイルを同期させる必要がなく、ファイルベースのAPIが自動的に正しいメタデータを生成します。

layout.js | page.js
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',
    },
  },
}
<head> 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"
/>
layout.js | page.js
export const metadata = {
  icons: {
    icon: [
      { url: '/icon.png' },
      new URL('/icon.png', 'https://example.com'),
      { url: '/icon-dark.png', media: '(prefers-color-scheme: dark)' },
    ],
    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',
      },
    ],
  },
}
<head> output
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="icon" href="https://example.com/icon.png" />
<link rel="icon" href="/icon-dark.png" media="(prefers-color-scheme: dark)" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
  rel="apple-touch-icon-precomposed"
  href="/apple-touch-icon-precomposed.png"
/>
<link
  rel="apple-touch-icon"
  href="/apple-icon-x3.png"
  sizes="180x180"
  type="image/png"
/>

知っておくと便利: msapplication-*メタタグはMicrosoft EdgeのChromiumビルドではサポートされなくなったため、もはや必要ありません。

themeColor

非推奨: metadata内のthemeColorオプションはNext.js 14以降非推奨です。代わりにviewport設定を使用してください。

colorScheme

非推奨: metadata内のcolorSchemeオプションはNext.js 14以降非推奨です。代わりにviewport設定を使用してください。

manifest

Web Application Manifest仕様で定義されているウェブアプリケーションマニフェスト。

layout.js | page.js
export const metadata = {
  manifest: 'https://nextjs.org/manifest.json',
}
<head> output
<link rel="manifest" href="https://nextjs.org/manifest.json" />

twitter

Twitter仕様は(驚くべきことに)X(旧Twitter)以外でも使用されます。

Twitter Cardマークアップリファレンスの詳細をご覧ください。

layout.js | page.js
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'], // 絶対URLである必要があります
  },
}
<head> 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" />
layout.js | page.js
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ロゴ',
    },
    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',
      },
    },
  },
}
<head> 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ロゴ" />
<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

非推奨: metadata内のviewportオプションはNext.js 14以降非推奨です。代わりにviewport設定を使用してください。

verification

layout.js | page.js
export const metadata = {
  verification: {
    google: 'google',
    yandex: 'yandex',
    yahoo: 'yahoo',
    other: {
      me: ['my-email', 'my-link'],
    },
  },
}
<head> 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

layout.js | page.js
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)',
      },
    ],
  },
}
<head> output
<meta
  name="apple-itunes-app"
  content="app-id=myAppStoreID, app-argument=myAppArgument"
/>
<meta name="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

layout.js | page.js
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',
    },
  },
}
<head> 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"
/>
layout.js | page.js
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,
    },
  },
}
<head> 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

歴史的な価値のある記録、文書、その他の資料のコレクションを記述します(出典)。

layout.js | page.js
export const metadata = {
  archives: ['https://nextjs.org/13'],
}
<head> output
<link rel="archives" href="https://nextjs.org/13" />

assets

layout.js | page.js
export const metadata = {
  assets: ['https://nextjs.org/assets'],
}
<head> output
<link rel="assets" href="https://nextjs.org/assets" />

bookmarks

layout.js | page.js
export const metadata = {
  bookmarks: ['https://nextjs.org/13'],
}
<head> output
<link rel="bookmarks" href="https://nextjs.org/13" />

category

layout.js | page.js
export const metadata = {
  category: 'technology',
}
<head> output
<meta name="category" content="technology" />

facebook

特定のFacebook Social PluginsのためにFacebookアプリやFacebookアカウントをウェブページに接続できますFacebookドキュメント

知っておくと便利: appIdまたはadminsのどちらかを指定できますが、両方は指定できません。

layout.js | page.js
export const metadata = {
  facebook: {
    appId: '12345678',
  },
}
<head> output
<meta property="fb:app_id" content="12345678" />
layout.js | page.js
export const metadata = {
  facebook: {
    admins: '12345678',
  },
}
<head> output
<meta property="fb:admins" content="12345678" />

複数のfb:adminsメタタグを生成したい場合は配列値を使用できます。

layout.js | page.js
export const metadata = {
  facebook: {
    admins: ['12345678', '87654321'],
  },
}
<head> output
<meta property="fb:admins" content="12345678" />
<meta property="fb:admins" content="87654321" />

pinterest

ウェブページでPinterest Rich Pinsを有効または無効にできます。

layout.js | page.js
export const metadata = {
  pinterest: {
    richPin: true,
  },
}
<head> output
<meta name="pinterest-rich-pin" content="true" />

other

すべてのメタデータオプションは組み込みサポートでカバーされるべきですが、サイト固有のカスタムメタデータタグや新しくリリースされたメタデータタグがあるかもしれません。otherオプションを使用して任意のカスタムメタデータタグをレンダリングできます。

layout.js | page.js
export const metadata = {
  other: {
    custom: 'meta',
  },
}
<head> output
<meta name="custom" content="meta" />

同じキーのメタタグを複数生成したい場合は配列値を使用できます。

layout.js | page.js
export const metadata = {
  other: {
    custom: ['meta1', 'meta2'],
  },
}
<head> output
<meta name="custom" content="meta1" /> <meta name="custom" content="meta2" />

未サポートのメタデータ

以下のメタデータタイプは現在組み込みサポートがありません。ただし、レイアウトやページ内で直接レンダリングすることは可能です。

タイプ

メタデータに型安全性を追加するには、Metadata タイプを使用します。組み込みのTypeScriptプラグインをIDEで使用している場合、手動でタイプを追加する必要はありませんが、必要に応じて明示的に追加することもできます。

metadata オブジェクト

layout.tsx | page.tsx
import type { Metadata } from 'next'

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

generateMetadata 関数

通常の関数
layout.tsx | page.tsx
import type { Metadata } from 'next'

export function generateMetadata(): Metadata {
  return {
    title: 'Next.js',
  }
}
非同期関数
layout.tsx | page.tsx
import type { Metadata } from 'next'

export async function generateMetadata(): Promise<Metadata> {
  return {
    title: 'Next.js',
  }
}
セグメントプロパティを使用
layout.tsx | page.tsx
import type { Metadata } from 'next'

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

export function generateMetadata({ params, searchParams }: Props): Metadata {
  return {
    title: 'Next.js',
  }
}

export default function Page({ params, searchParams }: Props) {}
親メタデータを使用
layout.tsx | page.tsx
import type { Metadata, ResolvingMetadata } from 'next'

export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  return {
    title: 'Next.js',
  }
}
JavaScriptプロジェクト

JavaScriptプロジェクトでは、JSDocを使用して型安全性を追加できます。

layout.js | page.js
/** @type {import("next").Metadata} */
export const metadata = {
  title: 'Next.js',
}
メタデータ推奨方法
<meta http-equiv="...">redirect()ミドルウェアセキュリティヘッダーを使用して適切なHTTPヘッダーを設定
<base>レイアウトまたはページ自体でタグをレンダリング
<noscript>レイアウトまたはページ自体でタグをレンダリング
<style>Next.jsでのスタイリングを参照
<script>スクリプトの使用を参照
<link rel="stylesheet" />レイアウトまたはページで直接スタイルシートをimport
<link rel="preload />ReactDOM preloadメソッドを使用
<link rel="preconnect" />ReactDOM preconnectメソッドを使用
<link rel="dns-prefetch" />ReactDOM prefetchDNSメソッドを使用

リソースヒント

<link>要素には、外部リソースが必要になる可能性があることをブラウザにヒントするためのrelキーワードがいくつかあります。ブラウザはこの情報を使用して、キーワードに応じてプリロード最適化を適用します。

メタデータAPIはこれらのヒントを直接サポートしていませんが、新しいReactDOMメソッドを使用してドキュメントの<head>に安全に挿入できます。

'use client'

import ReactDOM from 'react-dom'

export function PreloadResources() {
  ReactDOM.preload('...', { as: '...' })
  ReactDOM.preconnect('...', { crossOrigin: '...' })
  ReactDOM.prefetchDNS('...')

  return '...'
}

ページレンダリング(ブラウザ)ライフサイクルの早い段階でリソースの読み込みを開始します。MDNドキュメント

ReactDOM.preload(href: string, options: { as: string })
<head> output
<link rel="preload" href="..." as="..." />

オリジンへの接続を事前に開始します。MDNドキュメント

ReactDOM.preconnect(href: string, options?: { crossOrigin?: string })
<head> output
<link rel="preconnect" href="..." crossorigin />

リソースが要求される前にドメイン名の解決を試みます。MDNドキュメント

ReactDOM.prefetchDNS(href: string)
<head> output
<link rel="dns-prefetch" href="..." />

知っておくと良いこと:

  • これらのメソッドは現在、クライアントコンポーネントでのみサポートされており、初期ページロード時にはサーバーサイドレンダリングされます。
  • next/fontnext/imagenext/scriptなどのNext.js組み込み機能は、関連するリソースヒントを自動的に処理します。

動作

デフォルトフィールド

ルートがメタデータを定義していなくても、常に追加される2つのデフォルトのmetaタグがあります:

  • meta charsetタグはウェブサイトの文字エンコーディングを設定します。
  • meta viewportタグは、異なるデバイスに合わせてウェブサイトのビューポート幅とスケールを設定します。
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

知っておくと良いこと: デフォルトのviewportメタタグを上書きできます。

メタデータのストリーミング

generateMetadataによって返されるメタデータはクライアントにストリーミングされます。これにより、Next.jsはメタデータが解決され次第、HTMLにメタデータを注入できます。

ページメタデータは主にボットやクローラーを対象としているため、Next.jsはJavaScriptを実行し、完全なページDOMを検査できるボット(例: Googlebot)に対してメタデータをストリーミングします。ただし、HTML制限のあるボット(例: Twitterbot)に対しては、これらのボットがクロール中にJavaScriptを実行できないため、メタデータのレンダリングをブロックし続けます。

Next.jsは、受信リクエストのユーザーエージェントを自動的に検出し、ストリーミングメタデータを提供するか、フォールバックとしてブロッキングメタデータを提供するかを決定します。

このリストをカスタマイズする必要がある場合は、next.config.jshtmlLimitedBotsオプションを使用して手動で定義できます。Next.jsは、この正規表現に一致するユーザーエージェントがウェブページをリクエストしたときにブロッキングメタデータを受け取るようにします。

import type { NextConfig } from 'next'

const config: NextConfig = {
  htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}

export default config

htmlLimitedBots設定を指定すると、Next.jsのデフォルトリストが上書きされ、この動作を選択するユーザーエージェントを完全に制御できます。これは高度な動作であり、ほとんどの場合、デフォルトで十分です。

順序

メタデータは、ルートセグメントから始まり、最終的なpage.jsセグメントに最も近いセグメントまで順番に評価されます。例えば:

  1. app/layout.tsx (ルートレイアウト)
  2. app/blog/layout.tsx (ネストされたブログレイアウト)
  3. app/blog/[slug]/page.tsx (ブログページ)

マージ

評価順序に従って、同じルートの複数のセグメントからエクスポートされたメタデータオブジェクトは、ルートの最終的なメタデータ出力を形成するために浅くマージされます。重複するキーは、順序に基づいて置換されます。

これは、openGraphrobotsなどのネストされたフィールドを持つメタデータが、前のセグメントで定義されている場合、それらを定義する最後のセグメントによって上書きされることを意味します。

フィールドの上書き

app/layout.js
export const metadata = {
  title: 'Acme',
  openGraph: {
    title: 'Acme',
    description: 'Acme is a...',
  },
}
app/blog/page.js
export const metadata = {
  title: 'Blog',
  openGraph: {
    title: 'Blog',
  },
}

// 出力:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />

上記の例では:

  • app/layout.jstitleapp/blog/page.jstitleによって置換されます。
  • app/blog/page.jsopenGraphメタデータを設定しているため、app/layout.jsのすべてのopenGraphフィールドがapp/blog/page.js置換されます。openGraph.descriptionが存在しないことに注意してください。

セグメント間で一部のネストされたフィールドを共有しながら他のフィールドを上書きしたい場合は、それらを別の変数に抽出できます:

app/shared-metadata.js
export const openGraphImage = { images: ['http://...'] }
app/page.js
import { openGraphImage } from './shared-metadata'

export const metadata = {
  openGraph: {
    ...openGraphImage,
    title: 'Home',
  },
}
app/about/page.js
import { openGraphImage } from '../shared-metadata'

export const metadata = {
  openGraph: {
    ...openGraphImage,
    title: 'About',
  },
}

上記の例では、OG画像はapp/layout.jsapp/about/page.js間で共有され、タイトルは異なります。

フィールドの継承

app/layout.js
export const metadata = {
  title: 'Acme',
  openGraph: {
    title: 'Acme',
    description: 'Acme is a...',
  },
}
app/about/page.js
export const metadata = {
  title: 'About',
}

// 出力:
// <title>About</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme is a..." />

注記

  • app/layout.jstitleapp/about/page.jstitleによって置換されます。
  • app/about/page.jsopenGraphメタデータを設定していないため、app/layout.jsのすべてのopenGraphフィールドがapp/about/page.js継承されます。

バージョン履歴

バージョン変更点
v15.2.0generateMetadataへのストリーミングサポートを導入
v13.2.0viewportthemeColorcolorSchemeが非推奨になり、viewport設定が推奨されるようになりました
v13.2.0metadatagenerateMetadataが導入されました