Capítulo 162 de 456
Define metadata (title, description, Open Graph, etc.) de forma estática via o objeto metadata exportado, ou dinâmica via a função generateMetadata, ambos suportados apenas em Server Components. É a API central de SEO/shareability do App Router.
metadata object: export estático de layout.js/page.js quando o valor não depende de dados de request.generateMetadata function: export assíncrono/síncrono quando metadata depende de route params, dados externos ou metadata do parent; retorna um objeto Metadata.metadata/generateMetadata só funcionam em Server Components; para lógica client, mova para um componente filho separado com 'use client'.metadata e generateMetadata simultaneamente.fetch dentro de generateMetadata é memoizado automaticamente junto com generateStaticParams, layouts, pages e Server Components (React cache como fallback se fetch não estiver disponível).metadataBase: define URL base para resolver campos de metadata que exigem URL absoluta a partir de caminhos relativos; normaliza barras duplicadas.metadata quanto generateMetadata.generateMetadata resolver; tags aparecem no <body> para bots que executam JS, mas continuam bloqueando render (no <head>) para "HTML-limited bots" (ex. facebookexternalhit), detectados automaticamente via User-Agent e configuráveis via htmlLimitedBots.generateMetadata acessa dados de runtime (cookies(), headers(), params, searchParams) ou faz fetch não cacheado, o Next.js exige ou 'use cache' na função, ou um componente "dynamic marker" explícito envolto em <Suspense>, para deixar claro que o comportamento dinâmico é intencional.page.js final.Metadata de múltiplos segmentos são combinados de forma shallow; chaves duplicadas são substituídas pela ordem (campos aninhados como openGraph são sobrescritos por inteiro, não mesclados campo a campo).import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: Promise<{ id: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
const { id } = await params
const product = await fetch(`https://.../${id}`).then((res) => res.json())
const previousImages = (await parent).openGraph?.images || []
return {
title: product.title,
openGraph: { images: ['/some-specific-page-image.jpg', ...previousImages] },
}
}
export const metadata: Metadata = {
title: { template: '%s | Acme', default: 'Acme' },
}
// app/about/page.tsx
export const metadata: Metadata = { title: 'About' }
// Output: <title>About | Acme</title>
title.template no layout pai aplica prefixo/sufixo a títulos definidos em segmentos filhos; title.absolute ignoraria o template.export async function generateMetadata() {
'use cache'
const { title, description } = await db.query('site-metadata')
return { title, description }
}
'use cache' em generateMetadata quando o dado é externo mas não depende de runtime, evitando o erro de prerender bloqueado.| Campo principal | Uso |
|---|---|
title (string/default/template/absolute) | título do documento |
description | meta description |
metadataBase | base URL para campos relativos |
openGraph | title/description/url/images/videos/audio/locale/type |
robots | index/follow/googleBot |
icons | icon/shortcut/apple/other |
manifest | link para web app manifest |
twitter | card/title/description/images/app |
verification | google/yandex/yahoo/other |
appleWebApp | title/statusBarStyle/startupImage |
alternates | canonical/languages/media/types |
appLinks | ios/android/web |
archives, assets, bookmarks, pagination, category | metadata diversa (link tags) |
facebook, pinterest | integrações de plataforma específicas |
other | metadata custom arbitrária |
Deprecated desde v14 (usar generateViewport em vez): themeColor, colorScheme, viewport dentro de metadata.
Não suportado nativamente (renderizar direto no layout/page): <meta http-equiv>, <base>, <noscript>, <style>, <script>, <link rel="stylesheet">. Para preload/preconnect/dns-prefetch, usar ReactDOM.preload/preconnect/prefetchDNS em Client Component.
generateMetadata quando o valor não depende de request: prefira o objeto estático metadata, mais simples e sem custo de execução por request.openGraph do parent é preservado ao definir openGraph no filho: merge é shallow; definir openGraph no filho sobrescreve o objeto inteiro do parent (perde description, por exemplo, se não repetido).URL instance de metadataBase com 'use cache': use cache exige valores serializáveis; use url.toString().metadata e generateMetadata no mesmo segmento: não suportado.await connection() direto no componente Page para forçar dynamic marker: impede que o restante do conteúdo estático entre no shell; isole em componente próprio envolto em <Suspense>.metadata estático sempre que possível; reserve generateMetadata para dependência real em params/searchParams/dados externos/parent.openGraph image) para uma constante importada se quiser reaproveitar sem duplicar.searchParams só está disponível em page.js, não em layout.js.'use cache' ou declarar dynamic marker.icon.png, opengraph-image.tsx) sempre tem prioridade sobre os exports de código.opengraph-image/icon.viewport/themeColor/colorScheme.generateMetadata pode ser prerenderizado ou precisa de tratamento explícito para dados dinâmicos.generateMetadata.