SEO técnico com Next.js: como implementei metadata, JSON-LD e sitemap dinâmico na Nexus G
No artigo anterior, contei os bastidores gerais da construção da Nexus G. Aqui vou entrar no código de verdade: como o App Router do Next.js resolve, na prática, os quatro pilares que fazem um perfil profissional ser rastreado, indexado e ranqueado pelo Google metadata dinâmica, dados estruturados, sitemap e performance. O primeiro pilar é a Metadata API. Cada perfil da Nexus G é uma rota dinâmica, e cada uma precisa de title, description e Open Graph únicos usar o mesmo metadata genérico em todo perfil é um dos erros mais comuns que derruba ranqueamento por conteúdo duplicado. A solução do App Router é a função generateMetadata , que roda no servidor antes da página renderizar: // app/[username]/page.tsx export async function generateMetadata( { params }: { params: { username: string } } ): Promise<Metadata> { const profile = await getProfileByUsername(params.username); return { title: ${profile.name} - ${profile.role} | Nexus G, description: profile.bio.slice(0, 155), openGraph: { title: profile.name, description: profile.bio.slice(0, 155), images: [profile.avatarUrl], }, alternates: { canonical: https://nexusg.site/${profile.username}, }, }; } O dado vem direto do Supabase no momento da requisição, então qualquer atualização de bio ou avatar do usuário já reflete na próxima vez que o Google rastrear aquela página, sem precisar de novo deploy. O segundo pilar são os dados estruturados, o JSON-LD. Metadata comum diz ao Google o que é a página; o JSON-LD diz o que aquilo significa. Um perfil profissional se beneficia do schema Person combinado com ProfilePage , o que ajuda o Google a entender que aquela URL representa uma pessoa real, com cargo, habilidades e link de portfólio exatamente o tipo de contexto que abre espaço pra rich snippet na busca: function ProfileJsonLd({ profile }: { profile: Profile }) { const jsonLd = { '@context': 'https://schema.org', '@type': 'ProfilePage', mainEntity: { '@type': 'Person', name: profile.name, jobTitle: profile.role, description: profile.bio, url: https://nexusg.site/${profile.username}, knowsAbout: profile.skills, }, }; return ( <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} /> ); } Esse componente é renderizado dentro da própria página de perfil, como Server Component o que nos leva ao terceiro ponto, talvez o mais crítico de todos: manter o conteúdo real dentro de Server Components, nunca atrás de useEffect num Client Component. A maioria dos crawlers, incluindo os de IA que hoje também indexam conteúdo, não executa JavaScript da mesma forma que um navegador comum executa. Se a bio, as habilidades e os artigos de um perfil só aparecerem depois de uma chamada de API disparada no client, o rastreador simplesmente não vê aquele conteúdo. Na Nexus G, todo dado que compõe o perfil público é buscado no servidor antes da resposta HTML ser montada, garantindo que o que o crawler recebe é idêntico ao que a pessoa vê na tela. O quarto pilar é o sitemap dinâmico, resolvido pelo arquivo de convenção sitemap.ts na raiz do app: // app/sitemap.ts export default async function sitemap(): Promise<MetadataRoute.Sitemap> { const profiles = await getAllPublishedProfiles(); const posts = await getAllPublishedPosts(); const profileUrls = profiles.map((profile) => ({ url: https://nexusg.site/${profile.username}, lastModified: profile.updatedAt, changeFrequency: 'weekly' as const, priority: 0.8, })); const postUrls = posts.map((post) => ({ url: https://nexusg.site/${post.profileUsername}/${post.slug}, lastModified: post.updatedAt, changeFrequency: 'monthly' as const, priority: 0.6, })); return [...profileUrls, ...postUrls]; } Essa função roda a cada requisição do sitemap, o que significa que todo novo conteúdo publicado um perfil recém-criado ou um artigo recém-lançado entra automaticamente na lista sem intervenção manual. O robots.ts complementa isso liberando explicitamente rotas de perfil e conteúdo público, enquanto bloqueia rotas administrativas e de painel, que não têm nenhum motivo pra aparecer indexadas. Por fim, nada disso sustenta ranqueamento se a performance não acompanhar. Largest Contentful Paint, Interaction to Next Paint e Cumulative Layout Shift são hoje sinais diretos de ranqueamento, não só métrica de auditoria isolada. Na prática, isso significou usar next/image em toda imagem de perfil e capa, com prioridade explícita na imagem principal acima da dobra, usar next/font pra eliminar salto de layout por carregamento tardio de fonte, e revisar todo script de terceiro que entrava no perfil público cada um deles é candidato a atrasar interação e derrubar o INP se não for tratado com cuidado. Juntos, esses quatro pilares metadata dinâmica, dados estruturados, renderização no servidor com sitemap automático, e performance tratada como requisito são o que transforma um perfil de simples página bonita em um ativo que o Google realmente encontra, entende e recomenda. É engenharia de SEO aplicada linha por linha, não configuração de plugin.