SEO de Implantação do SvelteKit: Adaptadores, Pré-renderização e Renderização de Borda

As configurações de adaptador e pré-renderização por rota do SvelteKit decidem onde e quando suas páginas são renderizadas — e isso impulsiona TTFB, LCP e orçamento de rastreamento. Um mergulho profundo focado em implantação: escolhendo adapter-static/node/vercel/cloudflare/netlify, prerender = true/false/'auto', restrições de runtime de borda e construção de sitemap.xml e robots.txt.

Publicado pela primeira vez: 3 de jul. de 2026 · Última atualização: 3 de set. de 2026 · Avançado

O adaptador do SvelteKit e a configuração de pré-renderização por rota decidem onde e quando uma página é renderizada — HTML estático no momento da compilação, SSR em um servidor ou SSR na borda — e essa decisão impulsiona o TTFB, que alimenta o LCP e a capacidade de rastreamento. Escolha adapter-static para sites de conteúdo puro, um adaptador node/vercel/cloudflare com pré-renderização por rota para sites mistos de conteúdo e aplicativo, e um adaptador de borda quando o TTFB global importa (aceitando inicializações a frio e sem fs de Node). prerender = 'auto' é a ferramenta para sites mistos. Runtimes de borda não podem ler o sistema de arquivos. E o SvelteKit não gera sitemap.xml ou robots.txt — você os constrói como endpoints +server.js, com a estratégia dependendo do seu adaptador.

«> TL;DR — The adapter doesn’t change what SvelteKit renders — it changes

where and when: build-time static (adapter-static), request-time on a server you run (adapter-node), or request-time on serverless/edge functions (adapter-vercel/-netlify/-cloudflare). Per-route prerender = true builds static HTML and drops the route from the dynamic manifest; prerender = 'auto' prerenders and keeps it in the manifest — the tool for mixed /blog/[slug] sites. Edge runtimes run on V8 isolates: no Node fs, and cold starts hurt TTFB, which feeds LCP and (per Google’s crawl-budget doc) crawl capacity. SvelteKit generates no sitemap.xml or robots.txt — build them as +server.js endpoints, and note the strategy depends on the adapter. This is a narrower, deployment-focused companion to the SvelteKit SEO fundamentals article in this section; I assume you already know SvelteKit is SSR-by-default and won’t re-litigate that here. » (Tradução) (Síntese localizada do trecho dezoito, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«## The one idea that makes all of this click » (Tradução) (Síntese localizada do trecho dezenove, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«The adapter does not change what renders. It changes where and when. That’s the whole thing. The SvelteKit docs put it precisely: adapters “take the built app as input and generate output for deployment.” Evidência desta afirmação SvelteKit adapters take the built application as input and generate deployment-specific output. Escopo: Deployment output; adapter choice can still constrain supported runtime features. Confiança: alta · Verificado: SvelteKit: Adapters Your components, your load functions, your <svelte:head> metadata — identical across every adapter. What differs is: » (Tradução) (Síntese localizada do trecho vinte, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«- When the HTML is produced: at build time (static/prerendered) or at request time (SSR on a server, serverless function, or edge function).

  • Where it’s produced: on a single origin server, on a regional serverless function, or on an edge network close to the visitor. » (Tradução) (Síntese localizada do trecho vinte e um, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«Everything below is a consequence of those two axes. » (Tradução) (Síntese localizada do trecho vinte e dois, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«## Why deployment choices are SEO choices » (Tradução) (Síntese localizada do trecho vinte e três, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«The chain is short and well-documented: TTFB → LCP → crawl capacity. » (Tradução) (Síntese localizada do trecho vinte e quatro, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«Time to first byte is how long the host takes to start sending the response. A prerendered file served from a CDN cache has a near-zero TTFB. A server that has to render the page has a higher one. A cold-starting serverless or edge function can have a much higher one on the first hit. TTFB is a direct input to Largest Contentful Paint — you can’t paint what you haven’t received — and LCP is a Core Web Vitals signal. » (Tradução) (Síntese localizada do trecho vinte e cinco, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«The crawl side is where Google is most explicit. From the crawl-budget documentation: “If the site responds quickly for a while, the limit goes up, meaning more connections can be used to crawl. If the site slows down or responds with server errors, the limit goes down and Google crawls less.” And the best-practice line: “Make your pages efficient to load. If Google can load and render your pages faster, we might be able to read more content from your site.” A cold-starting edge function that’s slow to respond is subject to the same dynamic as a slow origin server. » (Tradução) (Síntese localizada do trecho vinte e seis, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«One honesty note up front: Google publishes no SvelteKit-specific guidance. There’s no doc or Search Off the Record episode naming SvelteKit adapters, prerender = 'auto', or edge cold starts. What I’m doing here is applying Google’s general rendering and crawl-budget guidance to SvelteKit’s specific mechanics — not quoting a rep who commented on SvelteKit, because none has. The Google framing that “server-side or pre-rendering is still a great idea because it makes your website faster for users and crawlers, and not all bots can run JavaScript” is the closest official anchor, and it’s framework-agnostic. » (Tradução) (Síntese localizada do trecho vinte e sete, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«## Choosing an adapter for SEO outcomes » (Tradução) (Síntese localizada do trecho vinte e oito, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### adapter-auto — the zero-config default, and its ceiling » (Tradução) (Síntese localizada do trecho vinte e nove, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«New SvelteKit projects ship with adapter-auto. It detects the platform — Vercel, Netlify, Cloudflare Pages, Azure, AWS — and installs the matching adapter at build time. It’s a fine starting point, but there’s a hard ceiling worth knowing: adapter-auto does not take any options. The moment you need { edge: true }, Cloudflare bindings, Vercel ISR, or any platform-specific configuration, you install the underlying adapter (adapter-vercel, adapter-cloudflare, etc.) directly. Treat auto as a scaffold, not a production decision. » (Tradução) (Síntese localizada do trecho trinta, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### adapter-static — full SSG, for content-first sites » (Tradução) (Síntese localizada do trecho trinta e um, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«adapter-static prerenders your whole site to static files at build time. No server runs; a host serves flat HTML. Evidência desta afirmação adapter-static prerenders a SvelteKit site as static files. Escopo: Routes must be prerenderable; performance outcomes depend on hosting and page design. Confiança: alta · Verificado: SvelteKit: Static site generation For a content-first site this is the strongest SEO profile you can have — lowest TTFB, no cold starts, nothing to fall over. The one requirement is the trap covered at length in the fundamentals article: SSR must stay on during the build, or you get empty shells instead of rendered HTML. I won’t re-explain that here beyond flagging it. » (Tradução) (Síntese localizada do trecho trinta e dois, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«The catch is rigidity. Anything that genuinely needs server logic per request (true search, per-user content, form handling without a third-party endpoint) can’t live on a purely static build — which is exactly what the next adapters are for. » (Tradução) (Síntese localizada do trecho trinta e três, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### adapter-node — a server you control » (Tradução) (Síntese localizada do trecho trinta e quatro, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«adapter-node produces a standalone Node.js server. You run it, you scale it, you own the TTFB. This is the most flexible option and the one with the fewest runtime surprises — full Node APIs, including fs. It’s a good fit when you have infrastructure already, need Node libraries that edge runtimes can’t run, or want predictable (non-cold-starting) response times from a warm server. The tradeoff is operational: you’re running a server, and its speed and uptime are now your crawl capacity. » (Tradução) (Síntese localizada do trecho trinta e cinco, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### adapter-vercel — serverless, edge, and ISR » (Tradução) (Síntese localizada do trecho trinta e seis, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«adapter-vercel deploys to Vercel’s serverless functions by default, with several SEO-relevant levers set per route via export const config: » (Tradução) (Síntese localizada do trecho trinta e sete, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

  • runtime: 'edge' move essa rota para o runtime de edge da Vercel (mais abaixo).
  • regions controla onde as funções serverless rodam — mais perto dos seus usuários (ou do seu banco de dados) significa menor latência.
  • isr habilita a Regeneração Estática Incremental: isr: { expiration: 60 } serve um ativo estático em cache e o regenera após a janela, dando “as vantagens de desempenho e custo de conteúdo pré-renderizado com a flexibilidade de conteúdo renderizado dinamicamente.” ISR é um verdadeiro quarto caminho entre puramente estático e puramente SSR — mas observe a ressalva da própria documentação: “Usar ISR em uma rota com export const prerender = true não terá efeito, pois a rota é pré-renderizada no momento do build.” ISR e prerender são alternativas, não empilháveis.

«### adapter-cloudflare — Workers/Pages, global edge » (Tradução) (Síntese localizada do trecho trinta e nove, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«adapter-cloudflare targets Cloudflare Workers and Pages — SSR on a global edge network, often the lowest TTFB for a geographically spread audience. The important constraint is the runtime: Workers run on V8 isolates, not Node. From the docs: “You can’t use fs in Cloudflare Workers.” Some Node APIs work only behind the nodejs_compat compatibility flag, and even then support isn’t one-to-one. If you were reading files at request time (a redirect map, a data file, custom OG-image inputs), that code needs a rethink — covered in the edge section below. » (Tradução) (Síntese localizada do trecho quarenta, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«(The older adapter-cloudflare-workers is deprecated; new projects use adapter-cloudflare, which handles both Workers and Pages. If you’re on the old one, migrating is the recommended path.) » (Tradução) (Síntese localizada do trecho quarenta e um, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### adapter-netlify — functions or Edge Functions (Deno) » (Tradução) (Síntese localizada do trecho quarenta e dois, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«adapter-netlify deploys to Netlify’s Node-based functions by default, or to Deno-based Edge Functions with edge: true. Same shape as Vercel: default serverless with an edge opt-in. One SvelteKit-specific footnote — Netlify Forms require the form’s page to be prerendered so Netlify can detect the form markup at deploy time, which is a small “prerender this route” requirement layered on top of the adapter choice. » (Tradução) (Síntese localizada do trecho quarenta e três, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### The decision, in one line each » (Tradução) (Síntese localizada do trecho quarenta e quatro, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

  • Site de conteúdo puro → adapter-static, prerenderize tudo.
  • Site de conteúdo com áreas dinâmicas → adapter-node/-vercel/-cloudflare, prerender = true no conteúdo, false/'auto' nas rotas dinâmicas.
  • App/dashboard com personalização → SSR-first (node ou edge), prerenderize apenas o shell estático (marketing, login).
  • Público global, crítico para TTFB → um adapter de edge para as rotas dinâmicas, aceitando as restrições de Node-API e a realidade do cold-start.

«(The Decision Tree tab walks this as a branching flow.) » (Tradução) (Síntese localizada do trecho quarenta e seis, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«## Prerendering strategy for mixed sites » (Tradução) (Síntese localizada do trecho quarenta e sete, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### What true / false / 'auto' actually do » (Tradução) (Síntese localizada do trecho quarenta e oito, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«export const prerender is a per-route (or per-layout) page option, and the three values aren’t just on/off: » (Tradução) (Síntese localizada do trecho quarenta e nove, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

  • true — construa esta rota como HTML estático no momento da build. Criticamente, é “excluído dos manifests usados para SSR dinâmico, tornando seu servidor (ou funções serverless/edge) menor.” Uma vez prerenderizada, a rota não pode cair de volta para renderização dinâmica — é estática, ponto final.
  • false — sempre renderize sob demanda. Sem arquivo estático.
  • 'auto' — a ferramenta para sites mistos. Ela prerenderiza a rota e a mantém no manifest do servidor dinâmico, para que a mesma rota possa ser servida estaticamente para caminhos conhecidos e renderizada no servidor para o restante. Isso é construído exatamente para o caso que a documentação descreve: uma rota como /blog/[slug] “onde você quer prerenderizar seu conteúdo mais recente/popular, mas renderizar no servidor a cauda longa.”

«Because prerendered routes shrink the server bundle, a mostly-prerendered site with a few 'auto'/false routes deploys a smaller, cheaper, faster function — an efficiency win independent of SEO. » (Tradução) (Síntese localizada do trecho cinquenta e um, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### Dynamic routes need an entries function » (Tradução) (Síntese localizada do trecho cinquenta e dois, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«The prerender crawler discovers pages by following <a> links from your entry points. That works for static routes, but a dynamic route like /blog/[slug] has no fixed URL for the crawler to find. If nothing links to a given slug, SvelteKit won’t know it exists — and you’ll hit the classic build error that routes “were marked as prerenderable, but were not prerendered.” » (Tradução) (Síntese localizada do trecho cinquenta e três, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«The fix is an explicit entries function (or config.kit.prerender.entries) that enumerates the parameter values: » (Tradução) (Síntese localizada do trecho cinquenta e quatro, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

// src/routes/blog/[slug]/+page.server.js
export const prerender = true;

export function entries() {
  return [
    { slug: 'hello-world' },
    { slug: 'sveltekit-deployment-seo' },
  ];
}

«In practice you generate that list from your CMS or content directory. Without it, prerendering only covers the slugs the link crawler happens to find. » (Tradução) (Síntese localizada do trecho cinquenta e seis, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### The /blog/[slug] pattern in the wild » (Tradução) (Síntese localizada do trecho cinquenta e sete, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«Put the two together and you have the canonical mixed-site setup: prerender = 'auto' plus an entries function that returns your recent and popular posts. Those get static HTML at build time; anything not in the list falls through to SSR on demand. New posts render dynamically until the next build prerenders them. It’s the pragmatic middle ground between “prerender all 40,000 posts every build” and “render every post on every request.” » (Tradução) (Síntese localizada do trecho cinquenta e oito, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«## Edge runtime constraints that affect SEO » (Tradução) (Síntese localizada do trecho cinquenta e nove, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### config.runtime = 'edge' is per-route (on Vercel) » (Tradução) (Síntese localizada do trecho sessenta, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«Edge isn’t an all-or-nothing switch. On Vercel it’s a per-route page option: » (Tradução) (Síntese localizada do trecho sessenta e um, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

// +page.server.js or +server.js
export const config = { runtime: 'edge' };

«That means you can push high-traffic, cacheable routes to the edge for low TTFB while keeping Node-dependent routes on the standard serverless (Node) runtime in the same deployment. Mix deliberately. » (Tradução) (Síntese localizada do trecho sessenta e três, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### No fs, no arbitrary Node APIs » (Tradução) (Síntese localizada do trecho sessenta e quatro, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«The edge runtimes — Cloudflare Workers, Vercel Edge Functions, Netlify’s Deno Edge Functions — don’t provide Node’s fs. Cloudflare’s docs: “You can’t use fs in Cloudflare Workers.” Vercel’s: “You can’t use fs in edge functions.” Both point to the same two escape hatches: use the read helper from $app/server to access bundled assets, or “prerender the routes in question” so the file access happens at build time instead of at request time. » (Tradução) (Síntese localizada do trecho sessenta e cinco, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«The SEO-adjacent cases where this bites: dynamic OG-image generation that reads a font or template file, file-based redirect maps, or a sitemap endpoint that reads content off disk. Any of those either moves to $app/server’s read() or moves to prerender/build time. It’s not a blocker — it’s a “know before you pick edge” constraint. » (Tradução) (Síntese localizada do trecho sessenta e seis, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### Cold starts and TTFB — when edge helps and when it doesn’t » (Tradução) (Síntese localizada do trecho sessenta e sete, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«Edge functions still cold-start. A cold edge function on its first request can be slower than a warm Node server, and dramatically slower than a prerendered file served from cache. Edge wins when the function stays warm or when it’s paired with aggressive caching so most requests never hit the function at all. It is not automatically the fastest option — “deploy to the edge” is not a synonym for “faster.” For a content site, prerendered static output beats edge SSR on TTFB every time, because there’s no function to start. » (Tradução) (Síntese localizada do trecho sessenta e oito, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«## Generating sitemap.xml and robots.txt (SvelteKit won’t) » (Tradução) (Síntese localizada do trecho sessenta e nove, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«This is the gap most SvelteKit tutorials skip and most audits catch. SvelteKit generates no sitemap.xml and no robots.txt automatically — regardless of adapter, regardless of how many pages you prerender. A fully static site with thousands of prerendered pages still ships with no sitemap unless you build one. » (Tradução) (Síntese localizada do trecho setenta, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### The +server.js endpoint pattern » (Tradução) (Síntese localizada do trecho setenta e um, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«The idiomatic sitemap is a route endpoint that returns XML with the right Content-Type: » (Tradução) (Síntese localizada do trecho setenta e dois, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

// src/routes/sitemap.xml/+server.js
export const prerender = true; // needed on adapter-static

export async function GET() {
  const urls = await getAllUrls(); // from your CMS/content
  const body = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map((u) => `  <url><loc>${u}</loc></url>`).join('\n')}
</urlset>`;

  return new Response(body, {
    headers: { 'Content-Type': 'application/xml' },
  });
}

«### The strategy depends on your adapter » (Tradução) (Síntese localizada do trecho setenta e quatro, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«Here’s the part that ties this whole article together: your sitemap strategy is downstream of your adapter choice. » (Tradução) (Síntese localizada do trecho setenta e cinco, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«- On adapter-static, the sitemap endpoint needs export const prerender = true so it’s included in the static output — there’s no server at runtime to generate it on request. It’s baked at build time, which means it’s only as fresh as your last build.

  • On a Node/serverless/edge adapter, the same endpoint can generate the sitemap dynamically per request from your CMS or database — always current, no rebuild needed. (On an edge adapter, remember the fs constraint: pull URLs from an API or binding, not a disk read.) » (Tradução) (Síntese localizada do trecho setenta e seis, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«So the “should my sitemap be static or dynamic?” question isn’t a separate decision — it falls out of the adapter you already chose. » (Tradução) (Síntese localizada do trecho setenta e sete, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«### robots.txt: static file vs. endpoint » (Tradução) (Síntese localizada do trecho setenta e oito, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«Two options. Drop a plain robots.txt in your static/ folder (served at /robots.txt automatically), which is the simplest choice and fine for most sites. Or generate it from a src/routes/robots.txt/+server.js endpoint when you need it to differ by environment (blocking crawlers on staging, allowing them in production, for instance). Either way, don’t block your /_app/ bundle or CSS — that breaks rendering for engines that do render. » (Tradução) (Síntese localizada do trecho setenta e nove, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

«If you’re coming at this from the broader framework or JavaScript-SEO angle, the “where and when does rendering happen” logic here is the same logic that governs JavaScript SEO generally, and the SvelteKit fundamentals piece in this section covers the rendering modes and metadata patterns this article builds on top of. » (Tradução) (Síntese localizada do trecho oitenta, parte um: o texto-fonte foi preservado para conferência na revisão nativa.)

Adicionar uma nota de especialista

Fixar uma citação de especialista

É uma pessoa nova? Crie o perfil não reivindicado dela em /admin/experts/ → Fixar uma citação de especialista primeiro.