Objeto Metadata y opciones de generateMetadata

Esta página cubre todas las opciones de Metadata basada en configuración con generateMetadata y el objeto metadata estático.

import { Metadata } from 'next'

// metadata estática
export const metadata: Metadata = {
  title: '...',
}

// o metadata dinámica
export async function generateMetadata({ params }) {
  return {
    title: '...',
  }
}
// metadata estática
export const metadata = {
  title: '...',
}

// o metadata dinámica
export async function generateMetadata({ params }) {
  return {
    title: '...',
  }
}

Es bueno saber:

  • El objeto metadata y la función generateMetadata solo son compatibles en Componentes de Servidor.
  • No puede exportar tanto el objeto metadata como la función generateMetadata desde el mismo segmento de ruta.

El objeto metadata

Para definir metadata estática, exporte un objeto Metadata desde un archivo layout.js o 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() {}

Consulte los Campos de Metadata para una lista completa de opciones compatibles.

Función generateMetadata

La metadata dinámica que depende de información dinámica, como parámetros de ruta actuales, datos externos o metadata en segmentos padres, puede configurarse exportando una función generateMetadata que devuelve un objeto 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> {
  // leer parámetros de ruta
  const id = params.id

  // obtener datos
  const product = await fetch(`https://.../${id}`).then((res) => res.json())

  // opcionalmente acceder y extender (en lugar de reemplazar) metadata padre
  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) {
  // leer parámetros de ruta
  const id = params.id

  // obtener datos
  const product = await fetch(`https://.../${id}`).then((res) => res.json())

  // opcionalmente acceder y extender (en lugar de reemplazar) metadata padre
  const previousImages = (await parent).openGraph?.images || []

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

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

Parámetros

La función generateMetadata acepta los siguientes parámetros:

  • props - Un objeto que contiene los parámetros de la ruta actual:

    • params - Un objeto que contiene los parámetros de ruta dinámica desde el segmento raíz hasta el segmento donde se llama a generateMetadata. Ejemplos:

      RutaURLparams
      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 - Un objeto que contiene los parámetros de búsqueda de la URL actual. Ejemplos:

      URLsearchParams
      /shop?a=1{ a: '1' }
      /shop?a=1&b=2{ a: '1', b: '2' }
      /shop?a=1&a=2{ a: ['1', '2'] }
  • parent - Una promesa de la metadata resuelta de segmentos de ruta padres.

Devuelve

generateMetadata debe devolver un objeto Metadata que contenga uno o más campos de metadata.

Es bueno saber:

  • Si la metadata no depende de información en tiempo de ejecución, debe definirse usando el objeto metadata estático en lugar de generateMetadata.
  • Las solicitudes fetch se memorizan automáticamente para los mismos datos en generateMetadata, generateStaticParams, Layouts, Pages y Componentes de Servidor. Se puede usar cache de React si fetch no está disponible.
  • searchParams solo está disponible en segmentos page.js.
  • Los métodos redirect() y notFound() de Next.js también pueden usarse dentro de generateMetadata.

Campos de Metadata

title

El atributo title se usa para establecer el título del documento. Puede definirse como una cadena simple o un objeto plantilla opcional.

String

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

Template object

import { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    template: '...',
    default: '...',
    absolute: '...',
  },
}
export const metadata = {
  title: {
    default: '...',
    template: '...',
    absolute: '...',
  },
}
Default

title.default puede usarse para proporcionar un título de respaldo a segmentos de ruta hijos que no definen un 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 = {}

// Salida: <title>Acme</title>
Template

title.template puede usarse para añadir un prefijo o sufijo a titles definidos en segmentos de ruta hijos.

import { Metadata } from 'next'

export const metadata: Metadata = {
  title: {
    template: '%s | Acme',
    default: 'Acme', // se requiere un valor default al crear una plantilla
  },
}
export const metadata = {
  title: {
    template: '%s | Acme',
    default: 'Acme', // se requiere un valor default al crear una plantilla
  },
}
import { Metadata } from 'next'

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

// Salida: <title>About | Acme</title>
export const metadata = {
  title: 'About',
}

// Salida: <title>About | Acme</title>

Es bueno saber:

  • title.template se aplica a segmentos de ruta hijos y no al segmento donde se define. Esto significa:

    • title.default es requerido cuando se añade un title.template.
    • title.template definido en layout.js no se aplicará a un title definido en un page.js del mismo segmento de ruta.
    • title.template definido en page.js no tiene efecto porque una página siempre es el segmento terminal (no tiene segmentos de ruta hijos).
  • title.template no tiene efecto si una ruta no ha definido un title o title.default.

Absolute

title.absolute puede usarse para proporcionar un título que ignore title.template establecido en segmentos padres.

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

// Salida: <title>About</title>
export const metadata = {
  title: {
    absolute: 'About',
  },
}

// Salida: <title>About</title>

Es bueno saber:

  • layout.js

    • title (string) y title.default definen el título predeterminado para segmentos hijos (que no definen su propio title). Aumentará title.template del segmento padre más cercano si existe.
    • title.absolute define el título predeterminado para segmentos hijos. Ignora title.template de segmentos padres.
    • title.template define una nueva plantilla de título para segmentos hijos.
  • page.js

    • Si una página no define su propio título, se usará el título resuelto del padre más cercano.
    • title (string) define el título de la ruta. Aumentará title.template del segmento padre más cercano si existe.
    • title.absolute define el título de la ruta. Ignora title.template de segmentos padres.
    • title.template no tiene efecto en page.js porque una página siempre es el segmento terminal de una ruta.

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

Campos básicos

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' }],
  colorScheme: 'dark',
  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 es una opción conveniente para establecer un prefijo de URL base para campos metadata que requieren una URL completa.

  • metadataBase permite que los campos metadata basados en URL definidos en el segmento de ruta actual y por debajo usen una ruta relativa en lugar de una URL absoluta que de otro modo sería requerida.
  • La ruta relativa del campo se combinará con metadataBase para formar una URL completa.
  • Si no se configura, metadataBase se rellena automáticamente con un valor predeterminado.
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" />

Es bueno saber:

  • metadataBase normalmente se establece en el app/layout.js raíz para aplicarse a campos metadata basados en URL en todas las rutas.
  • Todos los campos metadata basados en URL que requieren URLs absolutas pueden configurarse con una opción metadataBase.
  • metadataBase puede contener un subdominio, por ejemplo, https://app.acme.com o una ruta base, por ejemplo, https://acme.com/start/from/here.
  • Si un campo metadata proporciona una URL absoluta, metadataBase se ignorará.
  • Usar una ruta relativa en un campo metadata basado en URL sin configurar un metadataBase causará un error de compilación.
  • Next.js normalizará barras duplicadas entre metadataBase (por ejemplo, https://acme.com/) y un campo relativo (por ejemplo, /path) a una sola barra (por ejemplo, https://acme.com/path).

Valor predeterminado

Si no se configura, metadataBase tiene un valor predeterminado:

  • Cuando se detecta VERCEL_URL: https://${process.env.VERCEL_URL}, de lo contrario, recurre a http://localhost:${process.env.PORT || 3000}.
  • Al sobrescribir el valor predeterminado, recomendamos usar variables de entorno para calcular la URL. Esto permite configurar una URL para entornos de desarrollo local, staging y producción.

Composición de URL

La composición de URL favorece la intención del desarrollador sobre la semántica predeterminada de recorrido de directorios.

  • Las barras diagonales finales entre metadataBase y campos metadata se normalizan.
  • Una ruta "absoluta" en un campo metadata (que normalmente reemplazaría toda la ruta de la URL) se trata como una ruta "relativa" (comenzando desde el final de metadataBase).

Por ejemplo, dado el siguiente metadataBase:

import { Metadata } from 'next'

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

Cualquier campo metadata que herede el metadataBase anterior y establezca su propio valor se resolverá de la siguiente manera:

Campo metadataURL resuelta
/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',
        width: 800,
        height: 600,
      },
      {
        url: 'https://nextjs.org/og-alt.png',
        width: 1800,
        height: 1600,
        alt: 'Mi texto alternativo personalizado',
      },
    ],
    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="Mi texto alternativo personalizado" />
<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" />

Nota importante:

  • Puede ser más conveniente usar la API de Metadatos basada en archivos para imágenes de Open Graph. En lugar de tener que sincronizar la exportación de configuración con archivos reales, la API basada en archivos generará automáticamente los metadatos correctos.

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

Nota importante: Recomendamos usar la API de Metadatos basada en archivos para iconos siempre que sea posible. En lugar de tener que sincronizar la exportación de configuración con archivos reales, la API basada en archivos generará automáticamente los metadatos correctos.

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')],
    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="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"
/>

Nota importante: Las etiquetas meta msapplication-* ya no son compatibles en las versiones Chromium de Microsoft Edge, por lo que ya no son necesarias.

themeColor

Más información sobre theme-color.

Color de tema simple

layout.js | page.js
export const metadata = {
  themeColor: 'black',
}
<head> output
<meta name="theme-color" content="black" />

Con atributo media

layout.js | page.js
export const metadata = {
  themeColor: [
    { media: '(prefers-color-scheme: light)', color: 'cyan' },
    { media: '(prefers-color-scheme: dark)', color: 'black' },
  ],
}
<head> output
<meta name="theme-color" media="(prefers-color-scheme: light)" content="cyan" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="black" />

manifest

Un manifiesto de aplicación web, como se define en la especificación de Manifiesto de Aplicación Web.

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

Más información sobre la referencia de marcado de 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'],
  },
}
<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

Nota importante: La etiqueta meta viewport se establece automáticamente con los siguientes valores predeterminados. Por lo general, no es necesaria una configuración manual ya que los valores predeterminados son suficientes. Sin embargo, se proporciona la información para completitud.

layout.js | page.js
export const metadata = {
  viewport: {
    width: 'device-width',
    initialScale: 1,
    maximumScale: 1,
  },
}
<head> output
<meta
  name="viewport"
  content="width=device-width, initial-scale=1, maximum-scale=1"
/>

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

Describe una colección de registros, documentos u otros materiales de interés histórico (fuente).

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

other

Todas las opciones de metadatos deberían estar cubiertas usando el soporte incorporado. Sin embargo, puede haber etiquetas de metadatos personalizadas específicas para su sitio o nuevas etiquetas de metadatos recién lanzadas. Puede usar la opción other para renderizar cualquier etiqueta de metadatos personalizada.

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

Metadatos no admitidos

Los siguientes tipos de metadatos no tienen soporte incorporado actualmente. Sin embargo, aún pueden renderizarse en el layout o página directamente.

MetadatoRecomendación
<meta http-equiv="...">Use cabeceras HTTP apropiadas mediante redirect(), Middleware, Cabeceras de Seguridad
<base>Renderice la etiqueta en el layout o página directamente.
<noscript>Renderice la etiqueta en el layout o página directamente.
<style>Más información sobre estilos en Next.js.
<script>Más información sobre uso de scripts.
<link rel="stylesheet" />importe hojas de estilo directamente en el layout o página.
<link rel="preload />Use el método preload de ReactDOM
<link rel="preconnect" />Use el método preconnect de ReactDOM
<link rel="dns-prefetch" />Use el método prefetchDNS de ReactDOM

Pistas de recursos (Resource hints)

El elemento <link> tiene varias palabras clave rel que pueden usarse para indicar al navegador que es probable que se necesite un recurso externo. El navegador usa esta información para aplicar optimizaciones de precarga según la palabra clave.

Aunque la API de Metadatos no soporta directamente estas pistas, puede usar los nuevos métodos de ReactDOM para insertarlas de forma segura en el <head> del documento.

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

Inicia la carga de un recurso temprano en el ciclo de vida de renderizado de la página (navegador). Documentación MDN.

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

Inicia preventivamente una conexión a un origen. Documentación MDN.

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

Intenta resolver un nombre de dominio antes de que se soliciten los recursos. Documentación MDN.

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

Nota importante:

  • Estos métodos actualmente solo son compatibles en Componentes de Cliente, que aún se renderizan en el servidor en la carga inicial de la página.
  • Las características incorporadas de Next.js como next/font, next/image y next/script manejan automáticamente las pistas de recursos relevantes.
  • React 18.3 aún no incluye definiciones de tipos para ReactDOM.preload, ReactDOM.preconnect y ReactDOM.preconnectDNS. Puede usar // @ts-ignore como solución temporal para evitar errores de tipo.

Tipos

Puede agregar seguridad de tipos a sus metadatos usando el tipo Metadata. Si está usando el plugin de TypeScript incorporado en su IDE, no necesita agregar manualmente el tipo, pero aún puede hacerlo explícitamente si lo desea.

Objeto metadata

import type { Metadata } from 'next'

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

Función generateMetadata

Función regular

import type { Metadata } from 'next'

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

Función asíncrona

import type { Metadata } from 'next'

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

Con props de segmento

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) {}

Con metadatos padre

import type { Metadata, ResolvingMetadata } from 'next'

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

Proyectos JavaScript

Para proyectos JavaScript, puede usar JSDoc para agregar seguridad de tipos.

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

Historial de versiones

VersiónCambios
v13.2.0Se introdujeron metadata y generateMetadata.