Next.js SEO
SEO com Next.js em produção: guia completo
Configure SEO Next.js com renderização no servidor, metadados, URLs canônicas, sitemaps, JSON-LD, Core Web Vitals e verificações de versões em produção.
O SEO com Next.js em produção funciona como um contrato por rota: cada URL pública precisa de uma resposta útil, conteúdo renderizado no servidor, metadados consistentes, uma regra clara de indexação e uma verificação de lançamento que comprove que esses sinais chegaram à produção.
Defina uma função para cada rota indexável
O Next.js fornece APIs de renderização e metadados; ele não decide quais páginas merecem tráfego de busca. Comece definindo o leitor, a consulta de busca, a resposta, a URL canônica e a próxima ação de cada rota pública. Essa decisão distingue uma página útil de uma duplicata que apenas pode ser indexada.
Associe uma URL estável a cada intenção de busca distinta. Uma visão geral do produto, um guia de implementação, uma página de preços e uma referência de API podem abordar o mesmo produto, pois atendem a necessidades diferentes. Duas páginas que repetem a mesma resposta com títulos diferentes oferecem uma escolha menos útil aos leitores e criam mais uma página para a equipe manter.
Registre a decisão em um inventário de rotas antes de escrever os metadados. Inclua o padrão da rota, a fonte de dados, o modo de renderização, a regra de URL canônica, a possibilidade de indexação e o evento que aciona a atualização. O inventário se torna o contrato compartilhado entre conteúdo, engenharia e verificações de lançamento.
- —Indexe páginas que ofereçam uma resposta completa e útil por si só.
- —Mantenha fora do índice páginas privadas, vazias, de busca interna, de prévia e de filtros com pouco valor.
- —Use a URL canônica nos links internos, em vez de depender da tag canônica para corrigir uma navegação inconsistente.
- —Associe atualizações de conteúdo a eventos reais, como mudança no produto, revisão editorial ou atualização de estoque.
Inclua a resposta principal na primeira resposta HTML
No App Router, páginas e layouts são Server Components por padrão. Use esse comportamento para o título, a introdução, o texto principal, os dados do produto, a trilha de navegação e os links contextuais. Assim, a resposta inicial contém a resposta principal da página sem depender de uma requisição feita pelo navegador.
Um Client Component é adequado quando a funcionalidade precisa de estado, handler de evento, hook de ciclo de vida ou API do navegador. Mantenha o limite perto da interação. Uma calculadora de preços pode ser interativa sem transformar toda a página do produto em uma estrutura renderizada no cliente.
A escolha da renderização também define como manter os dados atualizados. A geração estática atende a conteúdo que muda com uma nova versão. A renderização no servidor atende a dados públicos específicos de cada requisição. A renderização com cache atende a dados compartilhados com um evento de invalidação definido. Escolha o modelo mais restrito que mantenha a resposta visível correta; não torne uma rota inteira dinâmica para dar suporte a um pequeno controle.
Criar uma hierarquia de metadados que sobreviva a rotas reais
Defina metadataBase, um modelo de título, a descrição padrão e os campos de compartilhamento comuns no layout raiz. Substitua os valores no layout ou na página mais específica responsável por eles. Rotas estáticas podem exportar metadata; rotas baseadas em dados podem usar generateMetadata. Ambas as APIs funcionam somente no servidor.
Trate os metadados aninhados como objetos completos na rota que os substitui. O Next.js combina os metadados da raiz até a página, mas os campos aninhados são substituídos, sem uma mesclagem recursiva. Um objeto openGraph definido na página pode descartar uma imagem herdada por acidente se fornecer apenas um novo título.
Versões atuais do Next.js podem transmitir metadados para bots que executam JavaScript e aguardar os metadados para bots limitados a HTML. Isso melhora o tempo de resposta, mas não torna inofensivas consultas lentas ou instáveis. Reutilize os dados resolvidos da página, trate entidades ausentes explicitamente e teste rotas com sucesso e com ausência.
app/layout.tsx and app/products/[slug]/page.tsx
// app/layout.tsx
import type { Metadata } from "next";
export const metadata: Metadata = {
metadataBase: new URL("https://www.example.com"),
title: { default: "Acme", template: "%s | Acme" },
description: "Tools for production engineering teams.",
openGraph: {
siteName: "Acme",
images: [{ url: "/og-default.png", width: 1200, height: 630 }],
},
};
// app/products/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
const { slug } = await params;
const product = await getProduct(slug);
if (!product) return { title: "Product not found", robots: { index: false } };
return {
title: product.name,
description: product.summary,
alternates: { canonical: "/products/" + product.slug },
openGraph: {
title: product.name,
description: product.summary,
images: product.images.map((image) => ({ url: image.url })),
},
};
}Trate URLs canônicas, redirecionamentos e robots como uma única política de URLs
Uma URL canônica identifica a versão preferida de conteúdo duplicado ou muito semelhante. Alinhe a preferência em redirecionamentos, anotações canônicas, links internos e sitemap. O Google considera redirecionamentos e rel=canonical sinais fortes, e a presença no sitemap um sinal mais fraco; sinais coerentes são mais fáceis de interpretar do que uma tag corretiva cercada de contradições.
Defina uma vez protocolo, host, regra de barra final, política de maiúsculas e minúsculas e comportamento dos parâmetros. Redirecione variantes que não devem continuar acessíveis. Use a URL canônica apontando para a própria página preferida quando isso ajudar a manter as URLs geradas consistentes.
Use os metadados robots para controlar se uma página acessível pode ser indexada e robots.txt para orientar o rastreamento. Nenhum dos dois protege conteúdo privado. A autorização deve rejeitar uma requisição não autenticada, independentemente dos cabeçalhos de rastreador enviados. Não inclua noindex na primeira resposta para tentar removê-lo no navegador: o Google pode parar antes de renderizar a alteração feita pelo JavaScript.
A page-level canonical and indexability rule
import type { Metadata } from "next";
export const metadata: Metadata = {
alternates: { canonical: "/guides/nextjs-seo" },
robots: { index: true, follow: true },
};Gere os arquivos para rastreadores a partir do conteúdo publicado
Gere sitemap.ts e robots.ts a partir da mesma fonte que define o conteúdo público. O sitemap deve conter URLs absolutas e canônicas que você quer que os mecanismos de busca descubram. Exclua rotas de conta, prévias, resultados de busca interna, caminhos redirecionados e combinações de parâmetros que não tenham valor por si só.
Use lastModified somente quando ele representar uma atualização significativa no conteúdo principal, nos dados estruturados ou nos links da página. O Google ignora os valores priority e changefreq do sitemap, portanto esses campos não corrigem uma lista de URLs desatualizada ou cheia de ruído. Para um catálogo grande, divida os sitemaps por família de conteúdo quando isso facilitar a geração, o monitoramento ou a definição de responsáveis.
Use robots.txt para orientar o rastreamento, sem depender dele para ocultar conteúdo. Uma URL cujo rastreamento é bloqueado ainda pode ser conhecida por links externos, e bloquear uma página pode impedir o rastreador de ver sua regra noindex. Retire rotas sensíveis dos meios públicos de descoberta e aplique o controle de acesso na aplicação.
- —Busque o sitemap de produção e confirme que a resposta contém XML e tem um código de status de sucesso.
- —Selecione URLs de cada família de conteúdo e verifique se todas abrem sem redirecionamento.
- —Compare a quantidade de URLs do sitemap com os registros publicados e canônicos na fonte de conteúdo.
- —Sinalize URLs geradas que tenham noindex, não existam, sejam redirecionadas ou apontem para uma URL canônica diferente.
app/sitemap.ts
import type { MetadataRoute } from "next";
const siteUrl = "https://www.example.com";
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await getPublishedPosts();
return posts
.filter((post) => post.indexable)
.map((post) => ({
url: new URL("/blog/" + post.slug, siteUrl).toString(),
lastModified: post.updatedAt,
}));
}Descrever entidades visíveis com JSON-LD preciso
Os dados estruturados identificam as entidades que a página já apresenta. Escolha o tipo conforme a finalidade real da página: Article para um texto editorial, Product para um item à venda, BreadcrumbList para a hierarquia ou SoftwareApplication para um produto de software real. Adicionar um tipo não muda a natureza da página.
Inclua as propriedades exigidas pelo recurso de busca que você quer habilitar e mantenha os valores coerentes com o conteúdo visível. Não invente avaliações, notas, preços, disponibilidade, autores ou datas de atualização. Uma marcação completa e precisa é mais útil do que um objeto enorme montado com campos sem respaldo na página.
Renderize o JSON-LD no servidor e sanitize o valor serializado quando ele contiver dados que você não controla totalmente. Valide a URL implantada com uma ferramenta de dados estruturados e depois inspecione o script por conta própria. A aprovação do analisador confirma a sintaxe; ela não comprova que a entidade seja fiel aos fatos, esteja atualizada ou seja elegível para um resultado avançado.
A server-rendered Article script
const article = {
"@context": "https://schema.org",
"@type": "Article",
headline: post.title,
description: post.excerpt,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
mainEntityOfPage: new URL("/blog/" + post.slug, siteUrl).toString(),
author: { "@type": "Organization", name: "Acme" },
};
const json = JSON.stringify(article).replaceAll("<", "\u003c");
return <script type="application/ld+json">{json}</script>;Proteja a experiência da página na divisão entre componentes
O trabalho de SEO falha quando a página pode ser indexada, mas é frustrante de usar. Restrinja a parte executada no cliente, reserve espaço para as imagens, carregue apenas os arquivos de fonte usados pelo design e ofereça conteúdo provisório útil enquanto seções secundárias mais lentas carregam. A primeira tela deve conter a resposta principal, em vez de uma estrutura vazia ou de um layout que muda conforme os recursos chegam.
Meça rotas representativas em produção. Uma página inicial cuidadosamente otimizada não basta. Largest Contentful Paint mede o carregamento, Interaction to Next Paint mede a capacidade de resposta e Cumulative Layout Shift mede a estabilidade visual. Avalie o percentil 75 das visitas reais quando houver dados de campo e depois use testes de laboratório para reproduzir uma regressão específica.
Quando uma rota ficar mais lenta, investigue a causa antes de remover conteúdo útil. Causas comuns incluem uma parte maior da página dentro de um Client Component, uma consulta de dados que bloqueia a renderização, um script de terceiros sem limites, uma imagem principal grande demais ou uma configuração de fonte que atrasa a exibição do texto. A correção deve preservar a função da página.
- —Meça pelo menos um artigo, uma página de listagem e uma página de detalhes baseada em dados.
- —Registre LCP, INP e CLS separadamente, em vez de reduzi-los a uma única pontuação.
- —Compare visitas diretas com navegação do lado do cliente entre rotas.
- —Teste novamente após uma implantação, pois a CDN, o ambiente de execução e o comportamento de terceiros afetam o resultado em produção.
Faça uma verificação de SEO do Next.js em 15 minutos antes do lançamento
A configuração de SEO não está concluída só porque o código parece correto. Compile a aplicação de produção, inicie o mesmo ambiente de execução que você pretende implantar e verifique a URL da versão candidata antes de atribuir o domínio canônico a ela. Uma consulta de metadados pode interromper a compilação, um redirecionamento pode eliminar uma seção e uma rota pode retornar uma página de erro personalizada com o código de status errado.
Teste uma página conhecida, um redirecionamento, uma página inexistente e uma rota dinâmica representativa. Inspecione a primeira resposta HTML para verificar título, descrição, URL canônica, regra robots, H1, resposta inicial, dados estruturados e links contextuais. Busque robots.txt e sitemap.xml separadamente e compare suas URLs com o inventário de rotas.
Registre as verificações junto da versão lançada, em vez de depender da memória. Se uma verificação essencial para SEO falhar, mantenha a versão atual em funcionamento, corrija a versão candidata e execute as mesmas verificações novamente. O resultado útil é uma rota em produção cuja resposta corresponda à política aprovada; uma lista de verificação perfeita, por si só, não resolve isso.
- —Confirme que a consulta principal e o resultado esperado pelo leitor ainda correspondem à página visível.
- —Confirme que a resposta principal e os links exploráveis existem na primeira resposta HTML.
- —Confirme que título, descrição, URL canônica, regra robots e H1 descrevem a mesma página.
- —Confirme que os dados estruturados correspondem aos fatos visíveis e são interpretados corretamente na URL implantada.
- —Confirme que URLs do sitemap são canônicas, indexáveis, retornam sucesso e têm datas relevantes.
- —Confirme que rotas representativas atendem aos limites de desempenho de produção definidos pela equipe.
A small production smoke test
npm run build
npm run start
curl -I https://preview.example.com/guides/nextjs-seo
curl -I https://preview.example.com/old-guide
curl -I https://preview.example.com/not-a-real-page
curl -s https://preview.example.com/guides/nextjs-seo | grep -E "<title|canonical|robots|application/ld\+json"
curl -I https://preview.example.com/robots.txt
curl -I https://preview.example.com/sitemap.xml