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.
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 SvelteKit já renderiza suas páginas no servidor — essa parte é resolvida. Esta página trata da próxima decisão: como seu site é construído e implantado. Um adapter empacota seu aplicativo SvelteKit para um host (um host de arquivos estáticos, um servidor Node ou um serviço como Vercel ou Cloudflare), e uma configuração de prerender por página decide se uma página é transformada em um arquivo HTML simples antecipadamente ou renderizada do zero a cada visita. Essas duas escolhas decidem a rapidez com que os crawlers obtêm seu HTML — e o SvelteKit não cria seu sitemap ou robots.txt, então você precisa adicioná-los você mesmo.
O que é um adapter (em termos simples)
Se você já construiu um site com SvelteKit, sabe que ele envia HTML real ao navegador — o conteúdo está lá antes de qualquer JavaScript ser executado. Ótimo. Esse é o problema difícil de SEO já resolvido (e se não estiver resolvido para você ainda, o artigo sobre fundamentos do SvelteKit nesta mesma seção cobre os modos de renderização e a armadilha do “shell vazio” que você deve evitar primeiro).
Um adapter é o pequeno plugin que pega sua build final do SvelteKit e a transforma em algo que um host específico pode executar. Evidence for this claim SvelteKit adapters transform a built application for deployment to a particular environment. Scope: SvelteKit adapters. Confidence: high · Verified: SvelteKit: Adapters Mesmo site, pacote diferente:
adapter-statictransforma cada página em um arquivo HTML simples, criado uma vez. Ótimo para um blog, documentação ou site de marketing que não muda por visitante.adapter-nodeenvolve seu aplicativo em um servidor Node.js que você mesmo executa.adapter-vercel,adapter-netlify,adapter-cloudflareempacotam para esses serviços de hospedagem, que renderizam páginas sob demanda — às vezes em servidores “na borda”, fisicamente próximos aos seus visitantes.
O conteúdo é idêntico em todos os casos. O que muda é quando o HTML é criado (antecipadamente ou a cada requisição) e onde (um servidor ou uma rede global).
Por que isso é uma decisão de SEO, não apenas técnica
O principal: velocidade. Uma página que já é um arquivo estático carrega quase instantaneamente. Uma página que precisa ser construída no servidor leva um momento. E o Google disse claramente que se seu site “responds quickly for a while, the limit goes up, meaning more connections can be used to crawl. If the site slows down… the limit goes down and Google crawls less.” (tradução) «Se o seu site responde rapidamente por um tempo, o limite aumenta, o que significa que mais conexões podem ser usadas para rastrear. Se o site ficar lento… o limite diminui e o Google rastreia menos.» Portanto, uma implantação lenta não apenas incomoda os usuários — pode significar que o Google lê menos do seu site.
A versão simples da decisão
- Um site de conteúdo (blog, documentação, marketing) → use
adapter-statice faça prerender de tudo. O mais rápido possível, nada para quebrar. - Um site de conteúdo com alguns elementos dinâmicos (busca, comentários) → use
um adapter de servidor (
node/vercel/cloudflare) e marque suas páginas de conteúdo comprerender = true, deixando os elementos dinâmicos para renderizar sob demanda. - Um aplicativo ou dashboard com páginas personalizadas para usuários logados → renderize no servidor (SSR), faça prerender apenas das páginas públicas de marketing.
Não se esqueça dos dois arquivos que o SvelteKit não criará para você
O SvelteKit não gera um sitemap.xml ou um robots.txt automaticamente. Você os
adiciona — geralmente como um pequeno arquivo de endpoint (sitemap.xml/+server.js)
e um arquivo na sua pasta static/ ou outro endpoint para
robots.txt. Evidence for this claim SvelteKit can serve static assets from its static directory and create custom responses with +server route files. Scope: Mechanisms for robots.txt and sitemap.xml; files are not generated automatically. Confidence: high · Verified: SvelteKit: Project structure SvelteKit: Routing É fácil esquecer porque a maioria dos frameworks que renderizam HTML para
você parecem “completos”. Esses dois não são.
Quer a versão mais aprofundada — o que cada adapter faz com a renderização, como
prerender = 'auto' lida com um site misto, por que as edge functions não podem
ler arquivos e como a estratégia de sitemap muda com seu adapter? Mude para a aba
Avançado.
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 = truepor 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: semfsdo 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).regionscontrola onde as funções serverless rodam — mais perto dos seus usuários (ou do seu banco de dados) significa menor latência.isrhabilita 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 comexport const prerender = truenã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 puro →
adapter-static, prerenderize tudo. - Site de conteúdo com áreas dinâmicas →
adapter-node/-vercel/-cloudflare,prerender = trueno 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 deexport const prerender = truepara 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.
Resumo de IA
Uma visão condensada da versão Avançada:
- O adaptador muda onde e quando, não o quê. Adaptadores “pegam o aplicativo compilado como entrada e geram saída para implantação” — mesmo conteúdo, diferente tempo (build vs. tempo de requisição) e localização (origem vs. edge).
- Por que é uma decisão de SEO: TTFB → LCP → capacidade de rastreamento. Google: se um site “responde rapidamente… o limite aumenta… Se o site fica lento… o Google rastreia menos.” Nenhuma orientação do Google menciona SvelteKit especificamente — esta é uma orientação geral aplicada à mecânica do SvelteKit.
- Adaptadores:
adapter-auto(zero configuração, sem opções);adapter-static(SSG, sites de conteúdo, menor TTFB);adapter-node(servidor que você controla, APIs completas do Node);adapter-vercel(serverless + edge + ISR);adapter-cloudflare(Workers de edge global, semfs;adapter-cloudflare-workersestá obsoleto);adapter-netlify(functions ou Deno Edge Functions). - Prerender:
truegera HTML estático e remove a rota do manifesto dinâmico;falsesempre faz SSR;'auto'faz prerender e mantém dinâmico — a ferramenta para sites mistos em/blog/[slug](prerender dos populares, SSR da cauda longa). - Rotas dinâmicas precisam de uma função
entriesou você encontra o erro “marcadas como pré-renderizáveis, mas não foram pré-renderizadas”. - Restrições de edge:
runtime: 'edge'é por rota (Vercel); semfs(“Você não pode usar fs em Cloudflare Workers” / edge functions) — useread()de$app/serverou prerender; cold starts podem tornar o edge mais lento que um servidor aquecido ou arquivo estático. - Sem sitemap/robots.txt integrado. Crie um endpoint
sitemap.xml/+server.js(prerender = trueemadapter-static; dinâmico em adaptadores de servidor/edge). robots.txt viastatic/ou um endpoint. - ISR ≠ prerender-plus: “Usar ISR em uma rota com
export const prerender = truenão terá efeito.” São alternativas.
Documentação oficial
Documentação de fonte primária do SvelteKit e dos mecanismos de busca.
SvelteKit
- Adapters • Documentação do SvelteKit — a visão geral: adaptadores pegam o aplicativo compilado e geram a saída de implantação.
- Zero-config deployments (adapter-auto) • Documentação do SvelteKit — detecção por plataforma e a limitação de “não aceita opções”.
- Node servers (adapter-node) • Documentação do SvelteKit — o servidor Node autônomo, variáveis de ambiente, desligamento gracioso.
- Static site generation (adapter-static) • Documentação do SvelteKit — SSG de site inteiro, o requisito de SSR e o aviso de SEO do fallback SPA.
- Vercel (adapter-vercel) • Documentação do SvelteKit —
runtimepor rota,regions,splite Regeneração Estática Incremental. - Cloudflare (adapter-cloudflare) • Documentação do SvelteKit — Workers/Pages, bindings
platform.env,nodejs_compate a limitação defs. - Cloudflare Workers (adapter-cloudflare-workers, obsoleto) • Documentação do SvelteKit — o adaptador legado obsoleto e o caminho de migração.
- Netlify (adapter-netlify) • Documentação do SvelteKit — Node Functions vs. Edge Functions baseadas em Deno (
edge: true) e o requisito de prerender para Forms. - Page options (prerender, ssr, csr, config) • Documentação do SvelteKit —
prerender = true/false/'auto', a funçãoentrieseconfigpor rota, incluindoruntime: 'edge'.
- Understand JavaScript SEO Basics — a fila de renderização e “nem todos os bots conseguem executar JavaScript.”
- Optimize your crawl budget — capacidade de rastreamento ligada à velocidade de resposta; “torne suas páginas eficientes para carregar.”
Bing / Microsoft
- Série bingbot: JavaScript, renderização dinâmica e cloaking. Oh, meu Deus! — A recomendação de pré-renderização/renderização dinâmica do Bing e o esclarecimento sobre cloaking.
- Desempenho rápido de front-end para o Microsoft Bing — A própria arquitetura de SSR + CDN/nós de borda do Bing como um ponto de prova no mundo real.
Citações da fonte
Declarações oficiais da documentação do SvelteKit, do Google e do Bing. Cada link é um link profundo que salta para a passagem citada na página de origem.
Documentação do SvelteKit — adaptadores e opções de página
- “adapter-auto does not take any options.” (tradução) «adapter-auto não aceita nenhuma opção.» — sobre o adaptador padrão de configuração zero. Ir para a citação
- Em
prerender = true— rotas pré-renderizadas são “excluded from manifests used for dynamic SSR, making your server (or serverless/edge functions) smaller.” (tradução) «excluídas dos manifestos usados para SSR dinâmico, tornando seu servidor (ou funções serverless/edge) menor.» Ir para a citação - Em
'auto'— o caso/blog/[slug]em que você quer “prerender your most recent/popular content but server-render the long tail.” (tradução) «pré-renderizar seu conteúdo mais recente/popular, mas renderizar no servidor a cauda longa.» Ir para a citação - Sobre a limitação de
fsna borda — “You can’t use fs in Cloudflare Workers.” (tradução) «Você não pode usar fs em Cloudflare Workers.» Ir para a citação - Sobre Vercel ISR vs. pré-renderização — “Using ISR on a route with export const prerender = true will have no effect, since the route is prerendered at build time.” (tradução) «Usar ISR em uma rota com export const prerender = true não terá efeito, pois a rota é pré-renderizada no momento da compilação.» Ir para a citação
Google — renderização e orçamento de rastreamento
- “Keep in mind 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.” (tradução) «Tenha em mente que a renderização no servidor ou a pré-renderização ainda é uma ótima ideia, pois torna seu site mais rápido para usuários e rastreadores, e nem todos os bots conseguem executar JavaScript.» Ir para a citação
- “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.” (tradução) «Se o site responder rapidamente por um tempo, o limite aumenta, o que significa que mais conexões podem ser usadas para rastrear. Se o site ficar lento ou responder com erros de servidor, o limite diminui e o Google rastreia menos.» Ir para a citação
- “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.” (tradução) «Torne suas páginas eficientes para carregar. Se o Google conseguir carregar e renderizar suas páginas mais rápido, talvez possamos ler mais conteúdo do seu site.» Ir para a citação
Bing — pré-renderização e sua própria arquitetura de borda
- “We encourage detecting our bingbot user agent, prerendering the content on the server side and outputting static HTML for such sites…” (tradução) «Incentivamos a detecção do nosso user agent do bingbot, a pré-renderização do conteúdo no lado do servidor e a saída de HTML estático para esses sites…» — Fabrice Canel e Frédéric Dubut, Microsoft Bing. Ir para a citação
- “User traffic routes first to the closest CDN node (called an ‘edge node’).” (tradução) «O tráfego de usuários roteia primeiro para o nó de CDN mais próximo (chamado de ‘nó de borda’).» — Bing Search Quality Insights, sobre a própria arquitetura de SSR + borda do Bing. Ir para a citação
Lista de verificação de SEO para implantação do SvelteKit
Uma passagem para confirmar que sua configuração de adaptador, pré-renderização e sitemap não prejudicará os rastreadores:
- Você migrou do
adapter-autopara um adaptador explícito se precisar de qualquer configuração (edge, ISR, bindings). - O adaptador corresponde ao tipo de site —
adapter-staticpara conteúdo puro, um adaptador de servidor/edge para qualquer coisa com lógica por solicitação. - As rotas de conteúdo estão com
prerender = true(ou'auto'); apenas rotas genuinamente dinâmicas ficam para SSR. - Rotas dinâmicas mistas (
/blog/[slug]) usamprerender = 'auto'com uma funçãoentriesenumerando caminhos conhecidos. - Nenhum erro de build “marcado como pré-renderizável, mas não foi pré-renderizado” sem resolução.
- Se qualquer rota usar
runtime: 'edge', ela não chama ofsdo Node — o acesso a arquivos usaread()de$app/serverou é pré-renderizado. - Você considerou cold starts em edge/serverless — armazenável em cache, estático, ou aquecido onde TTFB importa.
- Um endpoint de sitemap.xml existe (
prerender = trueemadapter-static; dinâmico em adaptadores de servidor/edge). - Um robots.txt existe (em
static/ou como endpoint+server.js) e não bloqueia/_app/ou CSS. - Você não está tentando empilhar ISR em uma rota
prerender = true(não tem efeito). - Você verificou o HTML renderizado e a velocidade de resposta na Inspeção de URLs do GSC e no PageSpeed Insights.
Os modelos mentais
1. Onde e quando, não o quê. O adaptador nunca muda seu conteúdo — ele muda quando o HTML é feito (tempo de build vs. tempo de solicitação) e onde (origem vs. edge). Toda pergunta de SEO de implantação se reduz a esses dois eixos. Pergunte-as antes de tocar na configuração.
2. A pré-renderização remove uma rota do servidor.
prerender = true não é apenas “tornar estático” — ele tira a rota do
manifesto dinâmico. Isso encolhe sua função e descarta um fallback dinâmico.
'auto' é a exceção: pré-renderizada e ainda no manifesto.
3. A divisão /blog/[slug].
O padrão para sites de conteúdo real: pré-renderize as entradas que você pode nomear
(a função entries retorna recentes/populares), SSR para a cauda longa. 'auto' é o
interruptor que torna ambos verdadeiros ao mesmo tempo.
4. Edge é uma troca, não uma atualização.
Edge compra proximidade geográfica (TTFB baixo quando aquecido) e custa APIs do Node
(sem fs) e risco de cold start. Ele vence um servidor Node aquecido apenas às vezes, e
perde para saída estática pré-renderizada em TTFB sempre. Escolha-o por um motivo, não por
padrão.
5. O sitemap segue o adaptador.
“Sitemap estático ou dinâmico?” não é uma decisão separada. adapter-static →
sitemap pré-renderizado, atualizado apenas no build. Adaptador de servidor/edge → sitemap
por solicitação, sempre atual. O adaptador já respondeu à pergunta.
6. Nada gera os dois arquivos. SvelteKit não cria sitemap.xml nem robots.txt, para qualquer adaptador. Se você não os escreveu, eles não existem. Incorpore isso à sua lista de verificação de lançamento.
Qual combinação de adaptador + pré-renderização devo escolher?
A pergunta central de “qual caminho eu sigo?” na implantação do SvelteKit é como este site deve ser entregue? Percorra seu site com isto:
1. Alguma página precisa de lógica de servidor por solicitação — autenticação, personalização, busca ao vivo, manipulação de formulários, dados por usuário? → Não (cada página é a mesma para cada visitante): vá para 2. → Sim: pule para 3.
2. Site de conteúdo puro (blog, docs, marketing).
→ Use adapter-static, defina prerender = true em todo o site (ou no
layout raiz). Adicione um sitemap.xml/+server.js pré-renderizado (prerender = true) e um
static/robots.txt. Menor TTFB, sem cold starts, nada para executar. Pare por aqui.
3. O site inteiro é dinâmico, ou apenas algumas rotas? → Apenas algumas rotas (majoritariamente conteúdo, alguns trechos dinâmicos): vá para 4. → Majoritariamente/ totalmente dinâmico (app, dashboard, ecommerce com dados por usuário): vá para 5.
4. Site de conteúdo com trechos dinâmicos.
→ Use um adaptador de servidor/edge (adapter-node, -vercel, ou
-cloudflare). Marque rotas de conteúdo com prerender = true, rotas dinâmicas
com false. Para rotas do tipo /blog/[slug] com conteúdo conhecido e popular, use
prerender = 'auto' + uma função entries. Gere o sitemap dinamicamente
a partir do seu CMS. Pronto.
5. App / dashboard / ecommerce (SSR-first). Agora escolha onde o SSR roda:
→ Latência previsível, bibliotecas Node, você tem infra: adapter-node
(servidor aquecido, APIs Node completas, sem surpresas de cold start).
→ Público global, TTFB importa mais, sem dependências Node pesadas: um adaptador de edge
(adapter-cloudflare, ou adapter-vercel com runtime: 'edge' por rota) —
aceite sem fs (use read() de $app/server ou pré-renderize) e cold starts.
Pré-renderize apenas o shell verdadeiramente estático (marketing, login).
Quarto caminho (somente Vercel): se uma rota é “majoritariamente estática, mas ocasionalmente
muda,” considere ISR (isr: { expiration }) em vez de prerender = true
— nunca ambos, pois “ISR em uma rota com export const prerender = true não terá
efeito.”
Meu sitemap deve ser estático ou dinâmico?
No adapter-static? → Endpoint de sitemap estático/pré-renderizado
(prerender = true). Ele é gerado no build; adequado para sites que recompilam na publicação.
Em um adaptador Node/serverless/edge? → Sitemap dinâmico gerado por requisição
a partir do seu CMS/DB — sempre atualizado, sem rebuild. (No edge, puxe URLs de uma API ou
binding, não de uma leitura de fs em disco.)
Nunca: deixe de enviar um sitemap porque “as páginas são todas estáticas.” Saída estática e descoberta de sitemap não têm relação — SvelteKit não gera nenhum dos dois arquivos para nenhum adaptador.
SEO de implantação SvelteKit — folha de referência
Adaptadores de relance
| Adaptador | Renderiza | Runtime | Nota de SEO |
|---|---|---|---|
adapter-static | Tempo de build (SSG) | nenhum | Menor TTFB, sem cold starts; sites de conteúdo |
adapter-node | Tempo de requisição (SSR) | Node | APIs Node completas (fs ✅); você executa o servidor |
adapter-vercel | Tempo de requisição | serverless / edge | runtime, regions por rota, ISR |
adapter-cloudflare | Tempo de requisição | V8 edge | Edge global; sem fs; nodejs_compat |
adapter-netlify | Tempo de requisição | Node / Deno edge | edge: true para Deno Edge Functions |
adapter-auto | (detecta os acima) | — | Não aceita opções — apenas scaffold |
Valores de prerender
| Valor | HTML estático? | No manifesto dinâmico? | Use para |
|---|---|---|---|
true | ✅ | ❌ (removido) | Rotas de conteúdo estático conhecidas |
false | ❌ | ✅ | Rotas genuinamente dinâmicas |
'auto' | ✅ | ✅ | /blog/[slug] — pré-renderize populares, SSR para cauda longa |
Regras rápidas
- Rotas dinâmicas pré-renderizadas → adicione uma função
entries(ou enfrente o erro “not prerendered”). runtime: 'edge'é por rota (Vercel) — misture rotas edge e Node.- Edge = sem
fs→ useread()de$app/serverou pré-renderize. - Cold starts tornam o edge mais lento que um servidor aquecido / arquivo estático no primeiro acesso.
- ISR ≠ prerender —
isrem uma rota comprerender = truenão faz nada. - Sem sitemap/robots.txt automáticos — crie ambos.
prerender = trueno endpoint do sitemap paraadapter-static; dinâmico em servidor/edge. - Nunca bloqueie
/_app/ou CSS no robots.txt.
Uma rota pré-renderizada está faltando na implantação
Causa provável: o crawler não conseguiu descobrir o caminho, um valor de entries está ausente ou a pré-renderização falhou. Correção: adicione links rastreáveis ou entradas explícitas e trate avisos de build como falhas de lançamento. Confirmação: o manifesto de saída contém a rota e a produção retorna HTML completo.
adapter-static falha em uma rota dinâmica
Causa provável: a rota não pode ser totalmente enumerada no momento do build. Correção: forneça entradas finitas, redesenhe a rota ou use um adaptador com suporte a servidor para esse caminho. Confirmação: o adaptador selecionado compila e cada rota representativa retorna a resposta pretendida.
Implantação de edge lança erros de filesystem ou API do Node
Causa provável: o código da rota ou uma dependência assume recursos do Node indisponíveis no runtime de edge. Correção: substitua a dependência, mova o trabalho para um serviço compatível ou escolha um adaptador Node. Confirmação: o SSR em produção é bem-sucedido sem exceções de runtime.
Sitemap ou robots.txt retorna HTML
Causa provável: uma rota de fallback captura o endpoint ou o handler +server define o corpo/cabeçalhos errados. Correção: crie handlers de endpoint explícitos com tipos de conteúdo corretos. Confirmação: requisições diretas retornam a resposta text/XML esperada e o status 200.
Metadados diferem entre rotas pré-renderizadas e SSR
Causa provável: os dados do head são carregados em caminhos de código diferentes ou dependem do estado do navegador. Correção: centralize a geração de metadados a partir de dados de página seguros para servidor/build. Confirmação: o HTML bruto para ambos os tipos de rota contém lógica equivalente de title, canonical e robots.
Confirme o que seu adaptador realmente enviou
O objetivo de escolher um adaptador e pré-renderizar é que um crawler receba HTML rápido e completo. Estas verificações confirmam que foi isso que realmente aconteceu — a partir da resposta bruta, não do navegador.
A página está pré-renderizada/SSR’d (conteúdo no HTML bruto)?
Um curl simples não executa JavaScript, então ele vê exatamente o que um crawler
que não renderiza vê.
macOS / Linux
# Raw HTML as the host sends it (no JS executed)
curl -sL "https://example.com/your-page/" -o raw.html
grep -o "Your unique headline text" raw.html # empty = CSR shell, not prerenderedWindows (PowerShell)
Invoke-WebRequest -Uri "https://example.com/your-page/" -OutFile raw.html
Select-String -Path raw.html -Pattern "Your unique headline text"O TTFB é rápido (ou uma função está em cold start)?
O TTFB alimenta o LCP e a capacidade de rastreamento, então meça-o. Acesse a URL a frio e depois a quente:
# Time to first byte, twice — a big first number then a small one = cold start
for i in 1 2; do
curl -s -o /dev/null -w "TTFB: %{time_starttransfer}s\n" "https://example.com/your-page/"
doneUma página pré-renderizada/estática deve ser consistentemente baixa. Um primeiro valor grande que cai na segunda visita é um clássico cold start de serverless/edge.
Esta rota foi pré-renderizada ou servida dinamicamente?
Hosts estáticos e CDNs geralmente revelam isso nos cabeçalhos (status de cache, age,
x-vercel-cache, cf-cache-status):
curl -sI "https://example.com/your-page/" | grep -iE "cache|age|x-vercel|cf-"Um HIT (ou um age diferente de zero) significa que você está recebendo conteúdo em cache/pré-renderizado;
um MISS/DYNAMIC em cada requisição significa que está renderizando por requisição.
O sitemap realmente existe e retorna XML?
Como o SvelteKit não gera um, verifique se o seu realmente está lá com o tipo de conteúdo correto:
curl -sI "https://example.com/sitemap.xml" | grep -iE "HTTP/|content-type"
# Want: 200 + content-type: application/xml (not text/html or a 404)One-liner no console do DevTools
Cole no console do navegador para comparar o DOM renderizado com o que um crawler precisa —
se o seu título está aqui, mas ausente na saída do curl acima, é
renderizado no cliente:
// Is the content in the DOM, and does the sitemap resolve?
console.log('headline in DOM:', document.body.innerText.includes('Your unique headline text'));
fetch('/sitemap.xml').then(r => console.log('sitemap status:', r.status, r.headers.get('content-type')));Verifique se o robots.txt não está bloqueando o bundle
curl -sL "https://example.com/robots.txt" | grep -iE "disallow.*(/_app|\.js|\.css)"Um Disallow correspondendo a /_app/ (saída empacotada do SvelteKit) ou ao seu CSS significa
que os mecanismos não conseguem renderizar a página — quase sempre um erro.
Ferramentas para depurar SEO de implantação do SvelteKit
- URL Inspection (Google Search Console) — a fonte da verdade. Teste uma URL ao vivo e verifique o HTML renderizado, a captura de tela e os recursos da página para confirmar que o conteúdo e os metadados estão presentes e que nada está bloqueado.
- PageSpeed Insights — a ferramenta recomendada pela própria documentação do SvelteKit; revela o TTFB e os Core Web Vitals (LCP/INP/CLS) que a sua escolha de adapter mais afeta.
- WebPageTest — waterfall + filmstrip para diagnosticar o TTFB e o tempo de cold start em deploys de edge/serverless.
curl -w "%{time_starttransfer}"— a verificação bruta mais rápida de TTFB e cold start (veja a aba Scripts).- Dashboards do host (Vercel / Cloudflare / Netlify Analytics) — contagens de invocação de funções, taxas de cold start e índices de cache hit por rota — a verdade absoluta para saber se edge/serverless é realmente rápido para você.
- Screaming Frog SEO Spider — rastreie com renderização de JS ligada/desligada para comparar o HTML bruto vs. renderizado em todo o site e confirmar que as rotas pré-renderizadas estão completas.
- Ahrefs Site Audit — revela sitemaps ausentes/bloqueados, cadeias de redirecionamento, canônicos quebrados e problemas de indexabilidade em escala.
Teste-se: SEO de Deploy no SvelteKit
Cinco perguntas rápidas sobre adapters, pré-renderização e renderização de edge no SvelteKit. Escolha uma resposta para cada uma e depois confira.
Recursos que valem seu tempo
Meus escritos relacionados
- JavaScript SEO: A Definitive Guide — minha referência completa sobre modos de renderização (SSR, renderização estática, pré-renderização e as armadilhas de CSR) que sustentam cada decisão de adapter aqui. Como eu disse lá, qualquer tipo de configuração de SSR, renderização estática ou pré-renderização vai funcionar bem para os mecanismos de busca — que é exatamente a rede de segurança por trás dessas escolhas de adapter.
- The Beginner’s Guide to Technical SEO — onde renderização, rastreamento e Core Web Vitals se encaixam no panorama geral.
Minhas palestras
- How Search Works (SlideShare) — minha explicação sobre rastreamento, renderização, indexação e ranqueamento, que é o pano de fundo para entender por que o TTFB e o tempo de renderização importam. (Minha ressalva padrão se aplica: “This is my understanding of systems… not going to be 100% complete or accurate.”) (tradução) «Esta é a minha compreensão dos sistemas… não vai ser 100% completa ou precisa.»
Da indústria
- Adapters • SvelteKit Docs — a visão geral autoritativa de cada adapter oficial e como eles são especificados no
svelte.config.js. - Page options (prerender, ssr, csr, config) • SvelteKit Docs — os valores de
prerenderpor rota, a funçãoentriese oconfigpor rota, incluindoruntime: 'edge', nas próprias palavras da equipe. - Vercel (adapter-vercel) • SvelteKit Docs — o runtime de edge, as regiões e a ressalva sobre ISR vs. pré-renderização.
- Cloudflare (adapter-cloudflare) • SvelteKit Docs — deploy em Workers/Pages, bindings e a limitação do
fs. - SvelteKit • Cloudflare Pages docs — a mecânica de deploy e os bindings de
platformdo lado da Cloudflare. - SvelteKit SEO: Your Secret Weapon (Okupter) — um guia prático sobre pré-renderização, meta tags e o padrão de sitemap/RSS com
+server.js. - A Deep Dive into SvelteKit’s Rendering Techniques (This Dot Labs) — mecânicas de SSR/SSG/CSR e configuração por rota/layout, com a ressalva de que “SSR pode ser caro” no server load.
- Understand JavaScript SEO Basics (Google Search Central) — a fila de renderização e “nem todos os bots conseguem executar JavaScript”, a orientação geral sob a qual cada escolha de adapter se encaixa.