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 ago. de 2026 · Avançado
Idiomas

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 — O adaptador não muda o que o SvelteKit renderiza — ele muda onde e quando: estático em tempo de build (adapter-static), em tempo de requisição em um servidor que você executa (adapter-node), ou em tempo de requisição em funções serverless/edge (adapter-vercel/-netlify/-cloudflare). prerender = true por rota gera HTML estático e remove a rota do manifesto dinâmico; prerender = 'auto' pré-renderiza e a mantém no manifesto — a ferramenta para sites mistos /blog/[slug]. Runtimes edge rodam em isolados V8: sem fs do Node, e cold starts prejudicam o TTFB, o que alimenta o LCP e (de acordo com o doc de crawl budget do Google) a capacidade de rastreamento. O SvelteKit não gera sitemap.xml ou robots.txt — crie-os como endpoints +server.js, e observe que a estratégia depende do adaptador. Este é um companheiro mais restrito e focado em deployment para o artigo de fundamentos de SEO do SvelteKit nesta seção; presumo que você já sabe que o SvelteKit é SSR por padrão e não vou reabrir esse assunto aqui.

A única ideia que faz tudo isso clicar

O adaptador não muda o que é renderizado. Ele muda onde e quando. É isso. A documentação do SvelteKit coloca com precisão: adaptadores “pegam o app construído como entrada e geram saída para deployment.” Evidence for this claim SvelteKit adapters take the built application as input and generate deployment-specific output. Scope: Deployment output; adapter choice can still constrain supported runtime features. Confidence: high · Verified: SvelteKit: Adapters Seus componentes, suas funções load, seus metadados <svelte:head> — idênticos em todos os adaptadores. O que difere é:

  • Quando o HTML é produzido: em tempo de build (estático/pré-renderizado) ou em tempo de requisição (SSR em um servidor, função serverless ou função edge).
  • Onde é produzido: em um servidor de origem único, em uma função serverless regional, ou em uma rede edge próxima ao visitante.

Tudo abaixo é uma consequência desses dois eixos.

Por que escolhas de deployment são escolhas de SEO

A cadeia é curta e bem documentada: TTFB → LCP → capacidade de rastreamento.

Time to first byte é quanto tempo o host leva para começar a enviar a resposta. Um arquivo pré-renderizado servido de um cache de CDN tem um TTFB quase zero. Um servidor que precisa renderizar a página tem um maior. Uma função serverless ou edge com cold start pode ter um TTFB muito maior no primeiro acesso. TTFB é uma entrada direta para o Largest Contentful Paint — você não pode pintar o que não recebeu — e LCP é um sinal de Core Web Vitals.

O lado do rastreamento é onde o Google é mais explícito. Da documentação de crawl budget: “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.” E a linha de melhores práticas: “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.” Uma função edge com cold start que demora a responder está sujeita à mesma dinâmica que um servidor de origem lento.

Uma nota de honestidade logo de início: o Google não publica orientação específica para SvelteKit. Não há doc ou episódio de Search Off the Record mencionando adaptadores do SvelteKit, prerender = 'auto' ou cold starts de edge. O que estou fazendo aqui é aplicar a orientação geral de renderização e crawl budget do Google às mecânicas específicas do SvelteKit — não citando um representante que comentou sobre SvelteKit, porque nenhum comentou. O enquadramento do Google de que “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” é a âncora oficial mais próxima, e é agnóstico de framework.

Escolhendo um adaptador para resultados de SEO

adapter-auto — o padrão de zero configuração, e seu teto

Novos projetos SvelteKit vêm com adapter-auto. Ele detecta a plataforma — Vercel, Netlify, Cloudflare Pages, Azure, AWS — e instala o adaptador correspondente no momento do build. É um bom ponto de partida, mas há um teto rígido que vale conhecer: adapter-auto não aceita opções. No momento em que você precisar de { edge: true }, bindings do Cloudflare, ISR da Vercel ou qualquer configuração específica da plataforma, você instala o adaptador subjacente (adapter-vercel, adapter-cloudflare, etc.) diretamente. Trate o auto como um scaffold, não uma decisão de produção.

adapter-static — SSG completo, para sites focados em conteúdo

adapter-static pré-renderiza todo o seu site em arquivos estáticos no momento do build. Nenhum servidor roda; um host serve HTML plano. Evidence for this claim adapter-static prerenders a SvelteKit site as static files. Scope: Routes must be prerenderable; performance outcomes depend on hosting and page design. Confidence: high · Verified: SvelteKit: Static site generation Para um site focado em conteúdo, este é o perfil de SEO mais forte que você pode ter — menor TTFB, sem cold starts, nada para falhar. O único requisito é a armadilha abordada em detalhes no artigo de fundamentos: SSR deve permanecer ligado durante o build, ou você obtém shells vazios em vez de HTML renderizado. Não vou reexplicar isso aqui além de sinalizar.

A desvantagem é a rigidez. Qualquer coisa que realmente precise de lógica de servidor por requisição (busca real, conteúdo por usuário, manipulação de formulários sem um endpoint de terceiros) não pode viver em um build puramente estático — que é exatamente para o que servem os próximos adaptadores.

adapter-node — um servidor que você controla

adapter-node produz um servidor Node.js autônomo. Você o executa, você o escala, você é dono do TTFB. Esta é a opção mais flexível e a que tem menos surpresas em tempo de execução — APIs Node completas, incluindo fs. É uma boa escolha quando você já tem infraestrutura, precisa de bibliotecas Node que os runtimes de edge não conseguem executar, ou quer tempos de resposta previsíveis (sem cold start) de um servidor aquecido. A troca é operacional: você está executando um servidor, e sua velocidade e uptime agora são sua capacidade de rastreamento.

adapter-vercel — serverless, edge e ISR

adapter-vercel faz deploy para as funções serverless da Vercel por padrão, com várias alavancas relevantes para SEO definidas por rota via export const config:

  • 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, edge global

adapter-cloudflare tem como alvo Cloudflare Workers e Pages — SSR em uma rede de edge global, muitas vezes o menor TTFB para um público geograficamente disperso. A restrição importante é o runtime: Workers rodam em isolados V8, não Node. Da documentação: “Você não pode usar fs em Cloudflare Workers.” Algumas APIs Node funcionam apenas atrás do flag de compatibilidade nodejs_compat, e mesmo assim o suporte não é um para um. Se você estava lendo arquivos no momento da requisição (um mapa de redirecionamento, um arquivo de dados, entradas personalizadas para OG-image), esse código precisa ser repensado — abordado na seção de edge abaixo.

(O mais antigo adapter-cloudflare-workers está obsoleto; novos projetos usam adapter-cloudflare, que lida tanto com Workers quanto com Pages. Se você está no antigo, migrar é o caminho recomendado.)

adapter-netlify — functions ou Edge Functions (Deno)

adapter-netlify faz deploy para as funções baseadas em Node da Netlify por padrão, ou para Edge Functions baseadas em Deno com edge: true. Mesma forma que a Vercel: serverless padrão com opt-in para edge. Uma nota específica do SvelteKit — os Netlify Forms exigem que a página do formulário seja prerenderizada para que a Netlify possa detectar a marcação do formulário no momento do deploy, o que é um pequeno requisito de “prerenderizar esta rota” sobreposto à escolha do adapter.

A decisão, em uma linha cada

  • Site de conteúdo puroadapter-static, prerenderize tudo.
  • Site de conteúdo com áreas dinâmicasadapter-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.

(A aba Decision Tree percorre isso como um fluxo ramificado.)

Estratégia de prerenderização para sites mistos

O que true / false / 'auto' realmente fazem

export const prerender é uma opção de página por rota (ou por layout), e os três valores não são apenas liga/desliga:

  • 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.”

Como as rotas prerenderizadas reduzem o bundle do servidor, um site majoritariamente prerenderizado com algumas rotas 'auto'/false faz deploy de uma função menor, mais barata e mais rápida — uma vitória de eficiência independente de SEO.

Rotas dinâmicas precisam de uma função entries

O crawler de prerenderização descobre páginas seguindo links <a> a partir dos seus pontos de entrada. Isso funciona para rotas estáticas, mas uma rota dinâmica como /blog/[slug] não tem URL fixa para o crawler encontrar. Se nada linka para um slug específico, o SvelteKit não saberá que ele existe — e você encontrará o clássico erro de build de que as rotas “foram marcadas como prerenderizáveis, mas não foram prerenderizadas.”

A correção é uma função entries explícita (ou config.kit.prerender.entries) que enumera os valores dos parâmetros:

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

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

Na prática, você gera essa lista a partir do seu CMS ou diretório de conteúdo. Sem ela, a prerenderização cobre apenas os slugs que o crawler de links encontra por acaso.

O padrão /blog/[slug] na prática

Junte os dois e você terá a configuração canônica de site misto: prerender = 'auto' mais uma função entries que retorna seus posts recentes e populares. Eles recebem HTML estático no momento da build; qualquer coisa que não estiver na lista cai para SSR sob demanda. Posts novos são renderizados dinamicamente até a próxima build prerenderizá-los. É o meio-termo pragmático entre “prerenderizar todos os 40 000 posts a cada build” e “renderizar cada post em cada requisição.”

Restrições do runtime de edge que afetam SEO

config.runtime = 'edge' é por rota (na Vercel)

Edge não é um interruptor de tudo ou nada. Na Vercel, é uma opção de página por rota:

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

Isso significa que você pode empurrar rotas de alto tráfego e cacheáveis para o edge para baixo TTFB enquanto mantém rotas dependentes de Node no runtime serverless (Node) padrão na mesma implantação. Misture deliberadamente.

Sem fs, sem APIs Node arbitrárias

Os runtimes de edge — Cloudflare Workers, Vercel Edge Functions, Netlify’s Deno Edge Functions — não fornecem o fs do Node. A documentação da Cloudflare: “You can’t use fs in Cloudflare Workers.” A da Vercel: “You can’t use fs in edge functions.” Ambas apontam para as mesmas duas saídas: use o helper read de $app/server para acessar ativos empacotados, ou “prerender the routes in question” para que o acesso a arquivos aconteça no momento do build em vez de no momento da requisição.

Os casos relacionados a SEO em que isso afeta: geração dinâmica de imagens OG que lê um arquivo de fonte ou modelo, mapas de redirecionamento baseados em arquivos ou um endpoint de sitemap que lê conteúdo do disco. Qualquer um deles ou migra para o read() de $app/server ou migra para o tempo de prerender/build. Não é um bloqueador — é uma restrição de “saiba antes de escolher edge”.

Cold starts e TTFB — quando o edge ajuda e quando não

As funções de edge ainda sofrem cold start. Uma função de edge fria em sua primeira requisição pode ser mais lenta do que um servidor Node aquecido, e dramaticamente mais lenta do que um arquivo pré-renderizado servido do cache. O edge vence quando a função permanece aquecida ou quando é combinado com cache agressivo para que a maioria das requisições nunca atinja a função. Não é automaticamente a opção mais rápida — “implantar no edge” não é sinônimo de “mais rápido.” Para um site de conteúdo, a saída estática pré-renderizada supera o SSR no edge em TTFB todas as vezes, porque não há função para iniciar.

Gerando sitemap.xml e robots.txt (o SvelteKit não gera)

Esta é a lacuna que a maioria dos tutoriais de SvelteKit ignora e a maioria das auditorias detecta. O SvelteKit não gera nenhum sitemap.xml e nenhum robots.txt automaticamente — independentemente do adaptador, independentemente de quantas páginas você pré-renderiza. Um site totalmente estático com milhares de páginas pré-renderizadas ainda é publicado sem sitemap, a menos que você crie um.

O padrão de endpoint +server.js

O sitemap idiomático é um endpoint de rota que retorna XML com o Content-Type correto:

// 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' },
  });
}

A estratégia depende do seu adaptador

Aqui está a parte que amarra todo este artigo: sua estratégia de sitemap é consequência da sua escolha de adaptador.

  • No adapter-static, o endpoint de sitemap precisa de export const prerender = true para ser incluído na saída estática — não há servidor em tempo de execução para gerá-lo sob demanda. Ele é gerado no momento do build, o que significa que só é tão atual quanto seu último build.
  • Em um adaptador Node/serverless/edge, o mesmo endpoint pode gerar o sitemap dinamicamente por requisição a partir do seu CMS ou banco de dados — sempre atual, sem necessidade de rebuild. (Em um adaptador de edge, lembre-se da restrição de fs: obtenha URLs de uma API ou binding, não de uma leitura de disco.)

Então a pergunta “meu sitemap deve ser estático ou dinâmico?” não é uma decisão separada — ela decorre do adaptador que você já escolheu.

robots.txt: arquivo estático vs. endpoint

Duas opções. Coloque um robots.txt simples na sua pasta static/ (servido em /robots.txt automaticamente), que é a escolha mais simples e suficiente para a maioria dos sites. Ou gere-o a partir de um endpoint src/routes/robots.txt/+server.js quando precisar que ele difira por ambiente (bloqueando crawlers em staging, permitindo-os em produção, por exemplo). De qualquer forma, não bloqueie seu bundle /_app/ ou CSS — isso quebra a renderização para mecanismos que renderizam.

Se você está vindo de uma perspectiva mais ampla de frameworks ou SEO para JavaScript, a lógica de “onde e quando a renderização acontece” aqui é a mesma lógica que rege o SEO para JavaScript de modo geral, e o artigo sobre fundamentos do SvelteKit nesta seção cobre os modos de renderização e padrões de metadados nos quais este artigo se baseia.

Add an expert note

Pin an expert quote

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