Объект Metadata и параметры generateMetadata

Эта страница охватывает все параметры Config-based Metadata с использованием generateMetadata и статического объекта metadata.

import { Metadata } from 'next'

// либо статические метаданные
export const metadata: Metadata = {
  title: '...',
}

// либо динамические метаданные
export async function generateMetadata({ params }) {
  return {
    title: '...',
  }
}
// либо статические метаданные
export const metadata = {
  title: '...',
}

// либо динамические метаданные
export async function generateMetadata({ params }) {
  return {
    title: '...',
  }
}

Полезно знать:

  • Объект metadata и функция generateMetadata поддерживаются только в Server Components.
  • Нельзя экспортировать одновременно объект metadata и функцию generateMetadata из одного сегмента маршрута.

Объект metadata

Для определения статических метаданных экспортируйте объект Metadata из файла layout.js или page.js.

import { Metadata } from 'next'

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

export default function Page() {}
export const metadata = {
  title: '...',
  description: '...',
}

export default function Page() {}

Полный список поддерживаемых параметров смотрите в разделе Поля Metadata.

Функция generateMetadata

Динамические метаданные, зависящие от динамической информации, такой как параметры текущего маршрута, внешние данные или metadata в родительских сегментах, могут быть заданы с помощью функции generateMetadata, которая возвращает объект Metadata.

import { Metadata, ResolvingMetadata } from 'next'

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

export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  // чтение параметров маршрута
  const id = params.id

  // получение данных
  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) {}
export async function generateMetadata({ params, searchParams }, parent) {
  // чтение параметров маршрута
  const id = params.id

  // получение данных
  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 }) {}

Параметры

Функция 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 - Промис с разрешёнными метаданными из родительских сегментов маршрута.

Возвращаемое значение

Функция generateMetadata должна возвращать объект Metadata, содержащий одно или несколько полей метаданных.

Полезно знать:

  • Если метаданные не зависят от информации во время выполнения, их следует определять с помощью статического объекта metadata, а не generateMetadata.
  • Запросы fetch автоматически мемоизируются для одних и тех же данных в generateMetadata, generateStaticParams, Layouts, Pages и Server Components. React cache можно использовать, если fetch недоступен.
  • searchParams доступны только в сегментах page.js.
  • Методы Next.js redirect() и notFound() также могут использоваться внутри generateMetadata.

Поля Metadata

title

Атрибут title используется для установки заголовка документа. Он может быть определён как простая строка или необязательный шаблонный объект.

Строка

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

Шаблонный объект

import { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    template: '...',
    default: '...',
    absolute: '...',
  },
}
export const metadata = {
  title: {
    default: '...',
    template: '...',
    absolute: '...',
  },
}
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 { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    template: '%s | Acme',
    default: 'Acme', // при создании шаблона требуется значение по умолчанию
  },
}
export const metadata = {
  title: {
    template: '%s | Acme',
    default: 'Acme', // при создании шаблона требуется значение по умолчанию
  },
}
import { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'About',
}

// Вывод: <title>About | Acme</title>
export const metadata = {
  title: 'About',
}

// Вывод: <title>About | Acme</title>

Полезно знать:

  • title.template применяется к дочерним сегментам маршрута, а не к сегменту, в котором он определён. Это означает:

    • title.default обязателен при добавлении title.template.
    • title.template, определённый в layout.js, не будет применяться к title, определённому в page.js того же сегмента маршрута.
    • title.template, определённый в page.js, не имеет эффекта, потому что страница всегда является конечным сегментом (у неё нет дочерних сегментов маршрута).
  • title.template не имеет эффекта, если маршрут не определил title или title.default.

Absolute

title.absolute может использоваться для предоставления заголовка, который игнорирует title.template, установленный в родительских сегментах.

import { Metadata } from 'next'

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

export const metadata: Metadata = {
  title: {
    absolute: 'About',
  },
}

// Вывод: <title>About</title>
export const metadata = {
  title: {
    absolute: 'About',
  },
}

// Вывод: <title>About</title>

Полезно знать:

  • layout.js

    • title (строка) и title.default определяют заголовок по умолчанию для дочерних сегментов (которые не определяют свой собственный title). Они будут дополнять title.template из ближайшего родительского сегмента, если он существует.
    • title.absolute определяет заголовок по умолчанию для дочерних сегментов. Он игнорирует title.template из родительских сегментов.
    • title.template определяет новый шаблон заголовка для дочерних сегментов.
  • page.js

    • Если страница не определяет свой собственный заголовок, будет использоваться заголовок ближайшего родителя.
    • title (строка) определяет заголовок маршрута. Он будет дополнять title.template из ближайшего родительского сегмента, если он существует.
    • title.absolute определяет заголовок маршрута. Он игнорирует title.template из родительских сегментов.
    • title.template не имеет эффекта в page.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 позволяет полям metadata, основанным на URL, определённым в текущем сегменте маршрута и ниже, использовать относительный путь вместо обязательного абсолютного URL.
  • Относительный путь поля будет объединён с metadataBase для формирования полного URL.
  • Если не настроен, metadataBase автоматически заполняется значением по умолчанию.
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 обычно устанавливается в корневом app/layout.js, чтобы применяться к полям metadata, основанным на URL, во всех маршрутах.
  • Все поля metadata, основанные на URL, которые требуют абсолютных URL, могут быть настроены с помощью параметра metadataBase.
  • metadataBase может содержать поддомен, например https://app.acme.com, или базовый путь, например https://acme.com/start/from/here.
  • Если поле metadata предоставляет абсолютный URL, metadataBase будет проигнорирован.
  • Использование относительного пути в поле metadata, основанном на URL, без настройки metadataBase вызовет ошибку сборки.
  • Next.js нормализует дублирующиеся слеши между metadataBase (например, https://acme.com/) и относительным полем (например, /path) до одного слеша (например, https://acme.com/path).

Значение по умолчанию

Если не настроено, metadataBase имеет значение по умолчанию:

  • Когда обнаружен VERCEL_URL: https://${process.env.VERCEL_URL}, в противном случае используется http://localhost:${process.env.PORT || 3000}.
  • При переопределении значения по умолчанию рекомендуется использовать переменные окружения для вычисления URL. Это позволяет настроить URL для локальной разработки, тестирования и рабочих окружений.

Композиция URL

Композиция URL отдаёт предпочтение намерениям разработчика перед семантикой обхода директорий по умолчанию.

  • Конечные слеши между metadataBase и полями metadata нормализуются.
  • "Абсолютный" путь в поле metadata (который обычно заменяет весь путь URL) обрабатывается как "относительный" путь (начиная с конца metadataBase).

Например, для следующего metadataBase:

import { Metadata } from 'next'

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

Любые поля metadata, которые наследуют указанный выше metadataBase и устанавливают собственное значение, будут разрешены следующим образом:

Поле 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: 'Мой альтернативный текст',
      },
    ],
    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: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="Мой альтернативный текст" />
<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

import type { Metadata } from 'next'

export const metadata: 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,
    },
  },
}
<head> 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

Полезно знать: Рекомендуем использовать файловый 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-* больше не поддерживаются в Chromium-сборках Microsoft Edge и больше не нужны.

themeColor

Устарело: Опция themeColor в metadata устарела в 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 markup reference.

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 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',
      },
    },
  },
}
<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 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

Устарело: Опция viewport в metadata устарела в 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="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

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 или аккаунт Facebook к вашей веб-странице для определённых Facebook Social Plugins Документация 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" />

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" />

Неподдерживаемые метаданные

Следующие типы метаданных в настоящее время не имеют встроенной поддержки. Однако их всё ещё можно отображать в самом макете или странице.

МетаданныеРекомендация
<meta http-equiv="...">Используйте соответствующие HTTP-заголовки через redirect(), Middleware, Security Headers
<base>Добавьте тег непосредственно в макет или страницу.
<noscript>Добавьте тег непосредственно в макет или страницу.
<style>Подробнее о стилизации в Next.js.
<script>Подробнее о использовании скриптов.
<link rel="stylesheet" />Импортируйте таблицы стилей напрямую в макет или страницу.
<link rel="preload />Используйте метод preload из ReactDOM
<link rel="preconnect" />Используйте метод preconnect из ReactDOM
<link rel="dns-prefetch" />Используйте метод prefetchDNS из ReactDOM

Ресурсные подсказки

Элемент <link> имеет ряд ключевых слов rel, которые можно использовать для указания браузеру, что внешний ресурс, скорее всего, понадобится. Браузер использует эту информацию для применения оптимизаций предварительной загрузки в зависимости от ключевого слова.

Хотя API метаданных напрямую не поддерживает эти подсказки, вы можете использовать новые методы ReactDOM для безопасного их добавления в <head> документа.

'use client'

import ReactDOM from 'react-dom'

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

  return null
}
'use client'

import ReactDOM from 'react-dom'

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

  return null
}

Начинает загрузку ресурса на раннем этапе жизненного цикла рендеринга страницы (в браузере). Документация 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="..." />

Полезно знать:

  • В настоящее время эти методы поддерживаются только в клиентских компонентах (Client Components), которые по-прежнему рендерятся на стороне сервера при первоначальной загрузке страницы.
  • Встроенные функции Next.js, такие как next/font, next/image и next/script, автоматически обрабатывают соответствующие ресурсные подсказки.
  • React 18.3 пока не включает определения типов для ReactDOM.preload, ReactDOM.preconnect и ReactDOM.preconnectDNS. Вы можете использовать // @ts-ignore в качестве временного решения, чтобы избежать ошибок типов.

Типы

Вы можете добавить проверку типов к своим метаданным, используя тип Metadata. Если вы используете встроенный плагин TypeScript в своей IDE, вам не нужно вручную добавлять тип, но вы всё равно можете явно указать его при желании.

Объект metadata

import type { Metadata } from 'next'

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

Функция generateMetadata

Обычная функция

import type { Metadata } from 'next'

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

Асинхронная функция

import type { Metadata } from 'next'

export async function generateMetadata(): Promise<Metadata> {
  return {
    title: 'Next.js',
  }
}

С параметрами сегмента

import type { Metadata } from 'next'

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

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

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

С родительскими метаданными

import type { Metadata, ResolvingMetadata } from 'next'

export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  return {
    title: 'Next.js',
  }
}

JavaScript проекты

Для проектов на JavaScript вы можете использовать JSDoc для добавления проверки типов.

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

История версий

ВерсияИзменения
v13.2.0viewport, themeColor и colorScheme устарели в пользу конфигурации viewport.
v13.2.0Введены metadata и generateMetadata.