SEO para Nuxt

O Nuxt oferece renderização no lado do servidor por padrão, mas isso é uma configuração por rota, não uma garantia — os rastreadores recebem HTML completo apenas nas rotas que mantêm esse comportamento. Modos de renderização, useSeoMeta(), o toolkit @nuxtjs/seo, hidratação e ressalvas do Nitro, Core Web Vitals e os erros que reduzem seu desempenho sem chamar atenção.

Publicado pela primeira vez: 26 de jun. de 2026 · Última atualização: 3 de ago. de 2026 · Avançado
Idiomas
1 sinal de evidência nesta página

O Nuxt renderiza páginas no servidor por padrão, então uma rota que mantém esse padrão oferece aos rastreadores um documento HTML completo em vez do shell vazio de uma SPA Vue comum — mas é uma configuração por rota: routeRules ou um ssr:false global podem transformar qualquer rota em CSR, portanto verifique a rota real em vez de presumir pelo nome do framework. A decisão fundamental é o modo de renderização por rota — SSR (padrão), SSG via nuxt generate ou regras híbridas — porque meta tags, schema e sitemaps vêm depois disso. Use useSeoMeta() para metadados, trate o pacote @nuxtjs/seo de Harlan Wilton como toolkit opcional de terceiros (não parte do núcleo do Nuxt) para robots/sitemap/OG/schema/canonical, nunca recorra à renderização dinâmica (o Google a descontinuou), verifique hidratação/payload e o comportamento de preset de implantação/cache do Nitro separadamente do HTML do servidor e lembre que os contratos de renderização de rastreadores de IA variam por provedor — SSR/SSG coloca o conteúdo no HTML bruto e maximiza a cobertura.

TL;DR — Nuxt’s padrão é renderização no lado fazer servidor, so a rota that keeps that padrão gets a complete DOM instead de the empty shell a plain Vue SPA ships — mas that’s a por rota outcome: ssr: false ou a routeRules override pode turn any rota em CSR ou hybrid, so test the rota real, não the project name. Rendering strategy é the foundational decision — SSR (padrão), SSG (nuxt generate), or hybrid routeRules — porque meta, schema, e sitemaps all come depois it. Use useSeoMeta() para meta tags (useHead() para the rest de the head, server-apenas variants when you don’t need reactivity), e treat Harlan Wilton’s @nuxtjs/seo bundle as an opcional third-party toolkit para robots/sitemap/OG/schema/canonical — não part de Nuxt core, e não proof its output é correct until you verificar it. Never usar dynamic rendering (Google deprecated it). AI-rastreador rendering varies by provedor — SSR/SSG maximizes raw-HTML coverage. Beyond the initial HTML, verify hidratação/payload, Nitro implantação presets e caching, e direct HTTP status independently — server HTML alone doesn’t prove any de those. The usual JS-SEO rules ainda apply: real <a href> links, don’t block JS/CSS, watch rendered vs. HTML bruto.

O Nuxt é a resposta fazer Vue ao problema das SPAs

Vue, by itself, ships a single-página application: an HTML shell plus JavaScript that builds the DOM in the browser. Nuxt é the meta-framework on top de Vue (running on the Nitro server engine in Nuxt 3, com Nuxt 4 following in 2025), e its whole motivo para existing — de an SEO standpoint — é that it renders on the server by padrão. Every página arrives as a fully-formed HTML document, which é exactly what Googlebot wants para ler sem having para execute JavaScript first. Plain Vue SEO é its own topic com its own failure modes; here I’m assuming you’ve picked Nuxt precisely so you don’t têm para fight the SPA problema.

This é the mesmo point I fazer about JavaScript generally: “any kind of SSR, static rendering, and prerendering setup is going to be fine for search engines. Gatsby, Next, Nuxt, etc., are all great.” Nuxt’s padrões são pointed the right way. Most Nuxt SEO problemas são people turning those padrões off, ou layering erros on top de them.

A estratégia de renderização é a base — decidida por rota, não por projeto

Before meta tags, antes schema, antes sitemaps, the question that decides everything é how faz the HTML get produced para this specific rota? Nuxt documents universal (server) rendering as the app-wide padrão, mas that padrão isn’t a rota-level guarantee: a global ssr: false switches the whole app para client rendering, e routeRules pode assign a diferente mode para any URL pattern. “This is a Nuxt app” tells you nothing about how one particular página renders — you têm para verificar the rota. Nuxt gives you five strategies:

ModeHow you set itSEO impactBest para
Universal / SSRDefault (ssr: true)Excellent — full HTML every solicitaçãoDynamic, personalized conteúdo
Static / SSGnuxt generateExcellent — HTML criado at deploy timeBlogs, docs, marketing
HybridrouteRules por rotaExcellent — mix por rotaLarge mixed-conteúdo sites
SPA / CSRssr: falsePoor para indexado conteúdoDashboards, admin panels
Edge-sideDeployment targetExcellent — low TTFBGlobal performance

The official Nuxt docs são blunt about why client-side rendering é the wrong choice para conteúdo: “Indexing and updating the content delivered via client-side rendering takes more time”, whereas com server (universal) rendering “web crawlers can directly index the page’s content.” Evidence for this claim Nuxt documents that universal rendering delivers HTML content immediately and allows crawlers to index it directly. Scope: Nuxt rendering; no indexing guarantee. Confidence: high · Verified: Nuxt: Rendering modes (Nuxt rendering docs.) CSR (ssr: false) é positioned para back-office, dashboards, e games — não anything you want indexado.

Hybrid rendering é the power move para grande sites. Route rules in nuxt.config.ts let you set the rendering e caching mode per URL pattern:

routeRules: {
  '/blog/**':     { prerender: true },        // SSG for the blog
  '/product/**':  { swr: 3600 },              // ISR-style: regenerate hourly
  '/admin/**':    { ssr: false },             // SPA for the admin area
  '/checkout/**': { ssr: true },              // always-fresh SSR
}

swr (stale-while-revalidate) e isr (incremental static regeneration) generate a página statically then refresh it in the background — ideal para high página-count e-commerce ou news where a full rebuild on every change isn’t practical. Nuxt Islands (<NuxtIsland>) render components sem shipping client-side JavaScript, cutting hidratação cost e helping INP — the Core Web Vital that’s most often the problema on Nuxt apps.

How para verify what you realmente shipped: View Source shows the HTML bruto the server sent; if your conteúdo é there, you’re server-rendering. DevTools’ Elements panel shows the rendered DOM. And GSC’s URL Inspection tool shows what Google realmente buscado e rendered — the source de truth. Don’t confiar “it looks fine in my browser.”

Como o Googlebot lida com um app Nuxt

Google processes any JavaScript app in three phases — rastrear, render, index — e the catch é timing: rendering happens in a queue, não instantly. As I put it in my JavaScript SEO guia, the renderer é patient — “there is no fixed timeout for the renderer… It’s really patient, and you should not be concerned.” But patient isn’t the mesmo as fast para fresh conteúdo. If you ship a client-rendered página, your conteúdo doesn’t exist para Google until that render wave runs; SSR e SSG close that gap porque the HTML é complete on the first buscar.

Two more things importar at scale. Rendering JavaScript é expensive — de my 2019 JavaScript SEO talk (Ungagged), rastrear costs go up by roughly 20× once Google tem para render (directional, mas the order de magnitude ainda holds). And Google takes the most restrictive directive across raw e rendered HTML — so a noindex injected by JavaScript vai win sobre an index in the HTML bruto, e vice versa. A canonical injected via JavaScript é respected apenas if there’s no canonical in the HTML bruto already. Keep your robots e canonical signals in the renderizado no servidor HTML, which Nuxt faz para you when SSR é on.

A realidade dos rastreadores de IA

This é the 2026 wrinkle. AI rastreadores — GPTBot, ClaudeBot, PerplexityBot, e the rest — generally don’t execute JavaScript at all. They index the HTML bruto e nothing else. So a client-rendered Nuxt página é effectively invisible para AI answer engines. SSR ou SSG isn’t apenas better para Google here; it’s the price de entry para answer engine optimization too. If you want your conteúdo cited by ChatGPT, Perplexity, ou Claude, it tem para ser in the HTML on first buscar.

Além fazer HTML inicial: payload, hidratação e códigos de status

Getting server HTML com your conteúdo in it é necessário mas não sufficient — several things pode ainda go wrong downstream de that first response, e “I checked View Source” doesn’t cover them:

  • Payload e hidratação. Universal rendering sends the HTML e a serialized dados payload the client usa para hydrate — attach event listeners e pick up where the server left off — sem re-busca. Server HTML looking right doesn’t prove hidratação succeeded, that client navigation reproduces the mesmo conteúdo, ou that the payload isn’t stale. If a página feels fine on first load mas breaks depois a client-side rota change, that’s a hidratação/payload problema, não a rendering-mode problema.
  • <ClientOnly> e browser-apenas conteúdo. Wrapping something in <ClientOnly> — comum para browser-API-dependent widgets — significa it’s absent de the server response even on an otherwise-universal rota. If your main conteúdo, a key link, ou your meta tags end up inside a client-apenas boundary, rastreadores e AI bots that apenas ler the HTML bruto miss it, regardless de your modo de renderização setting. Inspect the real response, não apenas the rendering mode config.
  • Status codes e redirects aren’t self-certifying. A Nuxt error página rendering in the browser, ou a navigateTo()/composable-driven redirect, doesn’t by itself prove what HTTP status the direct server response sent. Google’s orientação é explicit that meaningful códigos de status importar para rastreamento e indexação — confirm the real header com curl -I, não what the client-rendered error página displays.

None de this é an argument against universal rendering — it’s the reminder that “the HTML is server-rendered” é the first verificar, não the last one.

Nitro, presets de implantação e limites de cache

Nuxt’s server output é criado by Nitro, e Nitro compiles differently depending on the implantação preset you target (Node server, Cloudflare, Vercel, Netlify, static, e others). That importa para SEO porque presets e adapters pode differ in runtime APIs available, caching behavior, streaming suporte, regional implantação, e filesystem acesso — a rota rule ou server handler that funciona sob one preset isn’t guaranteed para behave identically sob another. Two consequences worth testing explicitly em vez disso than assuming:

  • Cache keys e invalidation são rota-specific, não automatic. swr e isr rota rules cache e regenerate output, mas a wrong cache key, missing invalidation, ou a caching header set by your implantação platform pode servir stale, personalized, ou inconsistent HTML para rastreadores. Check the real response age e any Cache-Control/Age headers on a live URL, não apenas the routeRules config.
  • Production parity isn’t guaranteed by staging behavior. A rota rendering correctly in local dev ou a preview implantação doesn’t confirm the production preset produces the mesmo output — server rotas, redirects, e error handling live in Nitro’s server layer, e that layer é the part most likely para differ by target. Test the production URL diretamente depois any implantação change, the mesmo way you’d verify modo de renderização.

Meta tags: useSeoMeta() e useHead()

Nuxt’s head management runs on Unhead, e it gives you two composables para diferente jobs.

useSeoMeta() é the one para reach para para SEO e social meta tags. It’s a flat, type-safe API com typed parameters. Evidence for this claim useSeoMeta is a typed Nuxt API for SEO and social meta tags. Scope: Current Nuxt composable. Confidence: high · Verified: Nuxt: useSeoMeta It ajuda evitar the classic Open Graph bug de usando name where you needed property:

useSeoMeta({
  title: 'My Page Title',
  ogTitle: 'My Page Title',
  description: 'Concise page-specific description with the key information first',
  ogDescription: 'Concise social description tailored to this page',
  ogImage: 'https://mysite.com/og-image.png', // must be an absolute URL
  twitterCard: 'summary_large_image',
})

useHead() é the general-finalidade head tool para everything else — scripts, link tags, body attributes, e título templates:

useHead({
  titleTemplate: '%s · My Site Name',
  htmlAttrs: { lang: 'en' },
})

The reliable layering pattern é: static padrões (charset, viewport, favicon) in nuxt.config.ts → site-wide título template e global OG padrões in app.vue → página-specific overrides via useSeoMeta() in the página component. A comum bug é putting useSeoMeta() in a layout instead de the página, which overwrites specific página tags com generic ones. And since mecanismos de busca ler the initial load, SEO meta generally doesn’t need para ser reactive — useServerHead() skips the client-side re-execution.

Qual API usar e o que ela realmente comprova:

APIScopeReactive?What it proves about output
useSeoMeta()Flat, typed SEO/social meta apenasYes (padrão)Sets typed properties correctly — não that the rota é unique, canonical, ou indexable; you ainda own that logic
useHead()Anything in <head> — scripts, links, attrs, título templateYes (padrão)General head controlar; mesmo caveat — API usar isn’t proof de a correct server response
useServerHead() / server-apenas callsSame as aboveNo — server apenas, skips client re-executionConfirms the tag ships once in server HTML; doesn’t confirm client navigation re-sets it if you rely on it there

Calling one de these composables tells you the API ran — it doesn’t by itself dizer you what a direct server response ou a client-side rota change realmente emits. Confirm com View Source ou curl, não apenas “I called 0.”

O ecossistema fazer módulo @nuxtjs/seo (Harlan Wilton) — opcional, não parte fazer núcleo

Nuxt core doesn’t ship a sitemap, a robots.txt, OG image generation, ou Schema.org out de the box — those são outside Nuxt’s own primitives (useHead, useSeoMeta, rota rules, modos de renderização). The comunidade fills that gap com Harlan Wilton’s @nuxtjs/seo — a separately-installed, third-party umbrella package (nuxtseo.com, currently at v5.x, actively mantido, targeting Nuxt 3,16+ e Nuxt 4) that bundles six modules. Installing it gives you sitemap, robots, OG-image, e schema generation — it doesn’t by itself guarantee the output é correct para your rotas; verify what it produces the mesmo way you’d verify anything else:

ModuleWhat it faz
@nuxtjs/robotsrobots.txt + meta robots + X-Robots-Tag headers
@nuxtjs/sitemapAuto XML sitemaps de páginas + dynamic rotas
nuxt-og-imageDynamic OG images (a Vue template → an image)
nuxt-schema-orgSchema.org JSON-LD structured dados
nuxt-seo-utilsCanonical URLs, breadcrumbs, padrões
nuxt-link-checkerBuild-time broken-link detection

Install the whole bundle com npx nuxt module add seo, ou grab individual modules (npx nuxt module add sitemap robots). A few behaviors worth knowing:

  • @nuxtjs/sitemap auto-generates de your pages/ directory plus dynamic rotas, splits em a sitemap index automatically past 50 000 URLs, oferece suporte i18n multi-language sitemaps, e tem criado-in IndexNow suporte. One thing para get right: Google ignores changefreq e priority; apenas an accurate lastmod importa, e apenas when conteúdo de fato changes.
  • @nuxtjs/robots generates robots.txt, the robots meta tag, e the X-Robots-Tag header — e by padrão it disallows all rastreadores on non-production environments, which é exactly the staging-indexation footgun that bites headless builds. It também gives you per-bot rules, so you pode block GPTBot specifically while leaving everyone else alone (ser intentional — block an AI rastreador e it won’t cite you).
  • nuxt-seo-utils handles canonical URLs e, usefully, strips tracking parameters (utm_*, fbclid, gclid) de canonicals automatically.

nuxt/image e Core Web Vitals

@nuxt/image é the image module: automatic responsive srcset, modern formats (WebP/AVIF), criado-in optimization por meio de CDN provedores, e lazy loading. Two rules carry most de the SEO value:

  • Never lazy-load the LCP image. Your hero image deve load eagerly; lazy-loading it delays your Largest Contentful Paint.
  • Always set width e height so the browser reserves space e you don’t take a Cumulative Layout Shift hit.
<NuxtImg
  src="/hero.jpg"
  width="1200"
  height="630"
  alt="Descriptive alt text"
  :loading="isHeroImage ? 'eager' : 'lazy'"
  format="webp"
/>

The 2026 targets para aim para (p75): LCP ≤ 2,5s, INP ≤ 200ms, CLS ≤ 0,1. On Nuxt apps, INP é the one that tends para suffer porque hidratação creates input lag — which é exactly what Nuxt Islands e <NuxtIsland> são para.

Nuxt Content + SEO

If you’re usando @nuxt/content (the markdown/MDX conteúdo module), the integration com @nuxtjs/seo é straightforward mas tem one ordering gotcha: load @nuxtjs/seo antes @nuxt/content in your modules array. You pode then set SEO in conteúdo frontmatter (title, description, robots, ogImage, schemaOrg) e pull it em your [slug].vue template com useSeoMeta() depois busca the conteúdo. This é the Nuxt-native version de the headless-CMS pattern, e the mesmo “rebuild what the plugin did” discipline applies.

Erros comuns de SEO no Nuxt

  1. Using SPA mode (ssr: false) para conteúdo you want indexado. The most expensive erro — e the one that faz you invisible para AI rastreadores.
  2. Relative URLs para OG images. ogImage must ser an absolute URL ou social previews break.
  3. useSeoMeta() in a layout instead de the página — generic tags overwrite página-specific ones.
  4. Not verifying rendered HTML — View Source ≠ DevTools ≠ what Google rendered. Use URL Inspection.
  5. Blocking JS/CSS in robots.txt — Google won’t render de blocked arquivos.
  6. Leaving the staging noindex/disallow in place depois launch (ou, conversely, forgetting @nuxtjs/robots blocks non-prod by padrão e wondering why prod é fine mas a custom env isn’t).
  7. Lazy-loading the LCP image — tanks your LCP.
  8. Missing width/height on images — CLS.
  9. changefreq/priority in sitemaps — Google ignores them; apenas lastmod counts.
  10. Recorrendo à renderização dinâmica. Google deprecated it — “dynamic rendering is a workaround and not a long-term solution” — e it apenas serves the engines you configure it para, missing Bing e every AI rastreador. With Nuxt you never need it: SSR e SSG already give rastreadores complete HTML.

llms.txt e AEO

llms.txt é a plain-text arquivo — robots.txt’s cousin — that ajuda AI tools navigate your conteúdo. The nuxt-llms module auto-generates /llms.txt e /llms-full.txt de Nuxt Content. As de late 2025 its principal consumidores são MCP servers e AI coding tools (Cursor, Claude Code) em vez disso than ChatGPT ou Perplexity diretamente, e it’s most útil para documentation sites e technical blogs — less so para e-commerce ou news. Worth adding if you’re a docs/dev site; não a priority otherwise.

Onde isso se encaixa

Nuxt SEO é realmente a concrete application de JavaScript SEO por meio de Nuxt’s own conventions — e it overlaps heavily com the SEO para a headless CMS topic when your Nuxt frontend pulls de a headless backend. The principles don’t change; Nuxt apenas gives you good padrões e a strong module ecosystem para implement them com.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.