Capítulo 162 de 456

generateMetadata

Core Idea

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.

Key Concepts

  • 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.
  • Server Component only: metadata/generateMetadata só funcionam em Server Components; para lógica client, mova para um componente filho separado com 'use client'.
  • Não pode coexistir: um mesmo route segment não pode exportar metadata e generateMetadata simultaneamente.
  • Memoização de fetch: 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.
  • File-based Metadata tem prioridade maior: sobrepõe tanto o objeto metadata quanto generateMetadata.
  • Streaming metadata: desde v15.2.0, Next.js pode enviar o UI inicial sem esperar 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.
  • Com Cache Components: se 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.
  • Ordering: metadata é avaliada do root layout até o segmento mais próximo do page.js final.
  • Merging: objetos 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).

Code Examples

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] },
  }
}
  • O que demonstra: metadata dinâmica que lê params, busca dado externo e estende (em vez de substituir) as imagens do parent.
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>
  • O que demonstra: 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 }
}
  • O que demonstra: sob Cache Components, usar 'use cache' em generateMetadata quando o dado é externo mas não depende de runtime, evitando o erro de prerender bloqueado.

Reference Tables

Campo principalUso
title (string/default/template/absolute)título do documento
descriptionmeta description
metadataBasebase URL para campos relativos
openGraphtitle/description/url/images/videos/audio/locale/type
robotsindex/follow/googleBot
iconsicon/shortcut/apple/other
manifestlink para web app manifest
twittercard/title/description/images/app
verificationgoogle/yandex/yahoo/other
appleWebApptitle/statusBarStyle/startupImage
alternatescanonical/languages/media/types
appLinksios/android/web
archives, assets, bookmarks, pagination, categorymetadata diversa (link tags)
facebook, pinterestintegrações de plataforma específicas
othermetadata 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.

Anti-patterns

  • Usar 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.
  • Assumir que 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).
  • Retornar URL instance de metadataBase com 'use cache': use cache exige valores serializáveis; use url.toString().
  • Exportar metadata e generateMetadata no mesmo segmento: não suportado.
  • Colocar 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>.

Key Takeaways

  1. Prefira o objeto metadata estático sempre que possível; reserve generateMetadata para dependência real em params/searchParams/dados externos/parent.
  2. Merge de metadata entre segmentos é shallow e por substituição total de campo aninhado; extraia valores compartilhados (ex. openGraph image) para uma constante importada se quiser reaproveitar sem duplicar.
  3. searchParams só está disponível em page.js, não em layout.js.
  4. Sob Cache Components, dado de metadata que depende de runtime exige decisão explícita: cachear com 'use cache' ou declarar dynamic marker.
  5. File-based Metadata (arquivos como icon.png, opengraph-image.tsx) sempre tem prioridade sobre os exports de código.

Connects To

  • generateImageMetadata: gera metadata para múltiplas variações de imagem, consumido por opengraph-image/icon.
  • generateViewport: substitui os campos depreciados viewport/themeColor/colorScheme.
  • File-based Metadata (Metadata Files): convenções de arquivo com prioridade mais alta que os exports de código.
  • cacheComponents / use cache: determinam se generateMetadata pode ser prerenderizado ou precisa de tratamento explícito para dados dinâmicos.
  • redirect / notFound: podem ser chamados dentro de generateMetadata.