generateMetadata
Puedes usar el objeto metadata
o la función generateMetadata
para definir metadatos.
El objeto metadata
Para definir metadatos estáticos, exporta un objeto Metadata
desde un archivo layout.js
o page.js
.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: '...',
description: '...',
}
export default function Page() {}
export const metadata = {
title: '...',
description: '...',
}
export default function Page() {}
Consulta los Campos de Metadatos para una lista completa de opciones soportadas.
Función generateMetadata
Los metadatos dinámicos que dependen de información dinámica, como parámetros de ruta actuales, datos externos o metadata
en segmentos padres, pueden configurarse exportando una función generateMetadata
que devuelve un objeto Metadata
.
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> {
// leer parámetros de ruta
const { id } = await params
// obtener datos
const product = await fetch(`https://.../${id}`).then((res) => res.json())
// opcionalmente acceder y extender (en lugar de reemplazar) metadatos padres
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 } = await params
// obtener datos
const product = await fetch(`https://.../${id}`).then((res) => res.json())
// opcionalmente acceder y extender (en lugar de reemplazar) metadatos padres
const previousImages = (await parent).openGraph?.images || []
return {
title: product.title,
openGraph: {
images: ['/some-specific-page-image.jpg', ...previousImages],
},
}
}
export default function Page({ params, searchParams }) {}
Es bueno saber:
- Los metadatos pueden agregarse a archivos
layout.js
ypage.js
.- Next.js resolverá automáticamente los metadatos y creará las etiquetas
<head>
relevantes para la página.- Las exportaciones del objeto
metadata
y la funcióngenerateMetadata
solo son compatibles en Componentes de Servidor.- No puedes exportar tanto el objeto
metadata
como la funcióngenerateMetadata
desde el mismo segmento de ruta.- Las solicitudes
fetch
dentro degenerateMetadata
se memorizan automáticamente para los mismos datos entregenerateMetadata
,generateStaticParams
, Layouts, Pages y Server Components.- Se puede usar
cache
de React sifetch
no está disponible.- Los metadatos basados en archivos tienen mayor prioridad y anularán el objeto
metadata
y la funcióngenerateMetadata
.
Referencia
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 desde donde se llama agenerateMetadata
. Ejemplos:Ruta URL params
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:URL searchParams
/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 los metadatos resueltos de los segmentos de ruta padres.
Devuelve
generateMetadata
debe devolver un objeto Metadata
que contenga uno o más campos de metadatos.
Es bueno saber:
- Si los metadatos no dependen de información en tiempo de ejecución, deben definirse usando el objeto
metadata
estático en lugar degenerateMetadata
.- Las solicitudes
fetch
se memorizan automáticamente para los mismos datos entregenerateMetadata
,generateStaticParams
, Layouts, Pages y Server Components. Se puede usarcache
de React sifetch
no está disponible.searchParams
solo está disponible en segmentospage.js
.- Los métodos
redirect()
ynotFound()
de Next.js también pueden usarse dentro degenerateMetadata
.
Campos de Metadatos
Se soportan los siguientes campos:
title
El atributo title
se usa para establecer el título del documento. Puede definirse como una cadena simple o un objeto plantilla opcional.
Cadena
export const metadata = {
title: 'Next.js',
}
<title>Next.js</title>
default
title.default
puede usarse para proporcionar un título de respaldo a segmentos de ruta hijos que no definen un title
.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: {
default: 'Acme',
},
}
import type { Metadata } from 'next'
export const metadata: Metadata = {}
// Salida: <title>Acme</title>
template
title.template
puede usarse para agregar un prefijo o sufijo a los titles
definidos en segmentos de ruta hijos.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: {
template: '%s | Acme',
default: 'Acme', // se requiere un valor por defecto al crear una plantilla
},
}
export const metadata = {
title: {
template: '%s | Acme',
default: 'Acme', // se requiere un valor por defecto al crear una plantilla
},
}
import type { 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
aplica a segmentos de ruta hijos y no al segmento donde se define. Esto significa:
title.default
es requerido cuando agregas untitle.template
.title.template
definido enlayout.js
no aplicará a untitle
definido en unpage.js
del mismo segmento de ruta.title.template
definido enpage.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 untitle
otitle.default
.
absolute
title.absolute
puede usarse para proporcionar un título que ignore title.template
establecido en segmentos padres.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: {
template: '%s | Acme',
},
}
export const metadata = {
title: {
template: '%s | Acme',
},
}
import type { 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
(cadena) ytitle.default
definen el título predeterminado para segmentos hijos (que no definen su propiotitle
). Aumentarátitle.template
del segmento padre más cercano si existe.title.absolute
define el título predeterminado para segmentos hijos. Ignoratitle.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
(cadena) 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. Ignoratitle.template
de segmentos padres.title.template
no tiene efecto enpage.js
porque una página siempre es el segmento terminal de una ruta.
description
export const metadata = {
description: 'El Framework de React para la Web',
}
<meta name="description" content="El Framework de React para la Web" />
Otros campos
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,
},
}
<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 de metadata
que requieren una URL completa.
metadataBase
permite que los campos demetadata
basados en URL definidos en el segmento de ruta actual y siguientes usen una ruta relativa en lugar de una URL absoluta que de otro modo sería requerida.- La ruta relativa del campo se compondrá con
metadataBase
para formar una URL completa.
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',
},
}
<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 archivo raízapp/layout.js
para aplicar a campos demetadata
basados en URL en todas las rutas.- Todos los campos de
metadata
basados en URL que requieren URLs absolutas pueden configurarse con una opciónmetadataBase
.metadataBase
puede contener un subdominio, p.ej.https://app.acme.com
o una ruta base, p.ej.https://acme.com/start/from/here
- Si un campo de
metadata
proporciona una URL absoluta,metadataBase
será ignorado.- Usar una ruta relativa en un campo de
metadata
basado en URL sin configurar unmetadataBase
causará un error de compilación.- Next.js normalizará barras duplicadas entre
metadataBase
(p.ej.https://acme.com/
) y un campo relativo (p.ej./path
) a una sola barra (p.ej.https://acme.com/path
)
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 finales entre
metadataBase
y campos demetadata
se normalizan. - Una ruta "absoluta" en un campo de
metadata
(que normalmente reemplazaría toda la ruta de URL) se trata como una ruta "relativa" (comenzando desde el final demetadataBase
).
Por ejemplo, dado el siguiente metadataBase
:
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://acme.com'),
}
export const metadata = {
metadataBase: new URL('https://acme.com'),
}
Cualquier campo de metadata
que herede el metadataBase
anterior y establezca su propio valor se resolverá de la siguiente manera:
Campo de metadata | URL resuelta |
---|---|
/ | https://acme.com |
./ | https://acme.com |
payments | https://acme.com/payments |
/payments | https://acme.com/payments |
./payments | https://acme.com/payments |
../payments | https://acme.com/payments |
https://beta.acme.com/payments | https://beta.acme.com/payments |
openGraph
export const metadata = {
openGraph: {
title: 'Next.js',
description: 'El Framework React para la Web',
url: 'https://nextjs.org',
siteName: 'Next.js',
images: [
{
url: 'https://nextjs.org/og.png', // Debe ser una URL absoluta
width: 800,
height: 600,
},
{
url: 'https://nextjs.org/og-alt.png', // Debe ser una URL absoluta
width: 1800,
height: 1600,
alt: 'Mi texto alternativo personalizado',
},
],
videos: [
{
url: 'https://nextjs.org/video.mp4', // Debe ser una URL absoluta
width: 800,
height: 600,
},
],
audio: [
{
url: 'https://nextjs.org/audio.mp3', // Debe ser una URL absoluta
},
],
locale: 'en_US',
type: 'website',
},
}
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="El Framework React para la 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="Mi texto alternativo personalizado" />
<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" />
export const metadata = {
openGraph: {
title: 'Next.js',
description: 'El Framework React para la Web',
type: 'article',
publishedTime: '2023-01-01T00:00:00.000Z',
authors: ['Seb', 'Josh'],
},
}
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="El Framework React para la 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: true,
follow: true,
nocache: false,
googleBot: {
index: true,
follow: true,
noimageindex: false,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
}
<meta name="robots" content="index, follow" />
<meta
name="googlebot"
content="index, follow, 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 cuando 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.
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',
},
},
}
<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'),
{ 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',
},
],
},
}
<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"
/>
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
Obsoleto: La opción
themeColor
enmetadata
está obsoleta a partir de Next.js 14. Utilice la configuraciónviewport
en su lugar.
colorScheme
Obsoleto: La opción
colorScheme
enmetadata
está obsoleta a partir de Next.js 14. Utilice la configuraciónviewport
en su lugar.
manifest
Un manifiesto de aplicación web, como se define en la especificación de Manifiesto de Aplicación Web.
export const metadata = {
manifest: 'https://nextjs.org/manifest.json',
}
<link rel="manifest" href="https://nextjs.org/manifest.json" />
twitter
La especificación de Twitter se usa (sorprendentemente) para más que solo X (anteriormente conocido como Twitter).
Más información sobre la referencia de marcado de Twitter Cards.
export const metadata = {
twitter: {
card: 'summary_large_image',
title: 'Next.js',
description: 'El Framework React para la Web',
siteId: '1467726470533754880',
creator: '@nextjs',
creatorId: '1467726470533754880',
images: ['https://nextjs.org/og.png'], // Debe ser una URL absoluta
},
}
<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="El Framework React para la Web" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
export const metadata = {
twitter: {
card: 'app',
title: 'Next.js',
description: 'El Framework React para la Web',
siteId: '1467726470533754880',
creator: '@nextjs',
creatorId: '1467726470533754880',
images: {
url: 'https://nextjs.org/og.png',
alt: 'Logo de 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',
},
},
},
}
<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="El Framework React para la Web" />
<meta name="twitter:card" content="app" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
<meta name="twitter:image:alt" content="Logo de 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
Obsoleto: La opción
viewport
enmetadata
está obsoleta a partir de Next.js 14. Utilice la configuraciónviewport
en su lugar.
verification
export const metadata = {
verification: {
google: 'google',
yandex: 'yandex',
yahoo: 'yahoo',
other: {
me: ['my-email', 'my-link'],
},
},
}
<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)',
},
],
},
}
<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
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',
},
},
}
<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"
/>
appLinks
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,
},
},
}
<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).
export const metadata = {
archives: ['https://nextjs.org/13'],
}
<link rel="archives" href="https://nextjs.org/13" />
assets
export const metadata = {
assets: ['https://nextjs.org/assets'],
}
<link rel="assets" href="https://nextjs.org/assets" />
bookmarks
export const metadata = {
bookmarks: ['https://nextjs.org/13'],
}
<link rel="bookmarks" href="https://nextjs.org/13" />
category
export const metadata = {
category: 'technology',
}
<meta name="category" content="technology" />
facebook
Puedes conectar una aplicación de Facebook o una cuenta de Facebook a tu página web para ciertos Plugins Sociales de Facebook Documentación de Facebook
Nota importante: Puedes especificar appId o admins, pero no ambos.
export const metadata = {
facebook: {
appId: '12345678',
},
}
<meta property="fb:app_id" content="12345678" />
export const metadata = {
facebook: {
admins: '12345678',
},
}
<meta property="fb:admins" content="12345678" />
Si deseas generar múltiples etiquetas meta fb:admins puedes usar un valor de array.
export const metadata = {
facebook: {
admins: ['12345678', '87654321'],
},
}
<meta property="fb:admins" content="12345678" />
<meta property="fb:admins" content="87654321" />
pinterest
Puedes habilitar o deshabilitar Pinterest Rich Pins en tu página web.
export const metadata = {
pinterest: {
richPin: true,
},
}
<meta name="pinterest-rich-pin" content="true" />
other
Todas las opciones de metadatos deberían estar cubiertas usando el soporte incorporado. Sin embargo, puede haber etiquetas meta personalizadas específicas para tu sitio o nuevas etiquetas meta recién lanzadas. Puedes usar la opción other
para renderizar cualquier etiqueta meta personalizada.
export const metadata = {
other: {
custom: 'meta',
},
}
<meta name="custom" content="meta" />
Si deseas generar múltiples etiquetas meta con la misma clave puedes usar un valor de array.
export const metadata = {
other: {
custom: ['meta1', 'meta2'],
},
}
<meta name="custom" content="meta1" /> <meta name="custom" content="meta2" />
Metadatos no compatibles
Los siguientes tipos de metadatos no tienen soporte incorporado actualmente. Sin embargo, aún pueden renderizarse en el layout o página directamente.
Tipos
Puede agregar seguridad de tipos a sus metadatos utilizando el tipo Metadata
. Si está utilizando el plugin integrado de TypeScript en su IDE, no necesita agregar el tipo manualmente, 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: 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) {}
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',
}
Metadatos | Recomendación |
---|---|
<meta http-equiv="..."> | Use encabezados HTTP apropiados mediante redirect() , Middleware, Security Headers |
<base> | Renderice la etiqueta en el layout o la página misma. |
<noscript> | Renderice la etiqueta en el layout o la página misma. |
<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 la página misma. |
<link rel="preload /> | Use método preload de ReactDOM |
<link rel="preconnect" /> | Use método preconnect de ReactDOM |
<link rel="dns-prefetch" /> | Use método prefetchDNS de ReactDOM |
Pistas de recursos
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 Metadata no admite directamente estas pistas, puede usar 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 '...'
}
'use client'
import ReactDOM from 'react-dom'
export function PreloadResources() {
ReactDOM.preload('...', { as: '...' })
ReactDOM.preconnect('...', { crossOrigin: '...' })
ReactDOM.prefetchDNS('...')
return '...'
}
<link rel="preload">
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 })
<link rel="preload" href="..." as="..." />
<link rel="preconnect">
Inicia preemptivamente una conexión a un origen. Documentación MDN.
ReactDOM.preconnect(href: string, options?: { crossOrigin?: string })
<link rel="preconnect" href="..." crossorigin />
<link rel="dns-prefetch">
Intenta resolver un nombre de dominio antes de que se soliciten los recursos. Documentación MDN.
ReactDOM.prefetchDNS(href: string)
<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 funciones integradas de Next.js como
next/font
,next/image
ynext/script
manejan automáticamente las pistas de recursos relevantes.
Comportamiento
Campos predeterminados
Hay dos etiquetas meta
predeterminadas que siempre se agregan, incluso si una ruta no define metadatos:
- La etiqueta meta charset establece la codificación de caracteres del sitio web.
- La etiqueta meta viewport establece el ancho y la escala del viewport para que el sitio web se ajuste a diferentes dispositivos.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
Nota importante: Puede sobrescribir la etiqueta meta
viewport
predeterminada.
Transmisión (streaming) de metadatos
Los metadatos devueltos por generateMetadata
se transmiten al cliente. Esto permite a Next.js inyectar metadatos en el HTML tan pronto como se resuelven.
Dado que los metadatos de página están dirigidos principalmente a bots y rastreadores, Next.js transmitirá metadatos para bots que pueden ejecutar JavaScript e inspeccionar el DOM completo de la página (por ejemplo, Googlebot
). Sin embargo, los metadatos seguirán bloqueando el renderizado de la página para bots limitados a HTML (por ejemplo, Twitterbot
) ya que estos no pueden ejecutar JavaScript mientras rastrean.
Next.js detecta automáticamente el agente de usuario de las solicitudes entrantes para determinar si servir metadatos transmitidos o recurrir a metadatos bloqueantes.
Si necesita personalizar esta lista, puede definirla manualmente usando la opción htmlLimitedBots
en next.config.js
. Next.js asegurará que los agentes de usuario que coincidan con esta expresión regular reciban metadatos bloqueantes al solicitar su página web.
import type { NextConfig } from 'next'
const config: NextConfig = {
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}
export default config
module.exports = {
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}
Especificar una configuración htmlLimitedBots
anulará la lista predeterminada de Next.js, permitiéndole control total sobre qué agentes de usuario deben optar por este comportamiento. Este es un comportamiento avanzado, y el valor predeterminado debería ser suficiente para la mayoría de los casos.
Orden
Los metadatos se evalúan en orden, comenzando desde el segmento raíz hasta el segmento más cercano al segmento final page.js
. Por ejemplo:
app/layout.tsx
(Layout raíz)app/blog/layout.tsx
(Layout anidado de blog)app/blog/[slug]/page.tsx
(Página de blog)
Fusión
Siguiendo el orden de evaluación, los objetos Metadata exportados desde múltiples segmentos en la misma ruta se fusionan superficialmente para formar la salida final de metadatos de una ruta. Las claves duplicadas se reemplazan según su orden.
Esto significa que los metadatos con campos anidados como openGraph
y robots
que se definen en un segmento anterior son sobrescritos por el último segmento que los define.
Sobrescribir campos
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme es...',
},
}
export const metadata = {
title: 'Blog',
openGraph: {
title: 'Blog',
},
}
// Salida:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />
En el ejemplo anterior:
title
deapp/layout.js
es reemplazado portitle
enapp/blog/page.js
.- Todos los campos
openGraph
deapp/layout.js
son reemplazados enapp/blog/page.js
porqueapp/blog/page.js
establece metadatosopenGraph
. Note la ausencia deopenGraph.description
.
Si desea compartir algunos campos anidados entre segmentos mientras sobrescribe otros, puede extraerlos en una variable separada:
export const openGraphImage = { images: ['http://...'] }
import { openGraphImage } from './shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'Inicio',
},
}
import { openGraphImage } from '../shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'Acerca de',
},
}
En el ejemplo anterior, la imagen OG se comparte entre app/layout.js
y app/about/page.js
mientras que los títulos son diferentes.
Heredar campos
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme es...',
},
}
export const metadata = {
title: 'Acerca de',
}
// Salida:
// <title>Acerca de</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme es..." />
Notas
title
deapp/layout.js
es reemplazado portitle
enapp/about/page.js
.- Todos los campos
openGraph
deapp/layout.js
son heredados enapp/about/page.js
porqueapp/about/page.js
no establece metadatosopenGraph
.
Historial de versiones
Versión | Cambios |
---|---|
v15.2.0 | Se introdujo soporte de transmisión para generateMetadata . |
v13.2.0 | viewport , themeColor y colorScheme obsoletos en favor de la configuración viewport . |
v13.2.0 | Se introdujeron metadata y generateMetadata . |