SEO per la distribuzione di SvelteKit: Adapter, Prerendering e Rendering Edge

Le impostazioni dell'adapter di SvelteKit e del prerender per rotta decidono dove e quando vengono renderizzate le tue pagine — e questo determina TTFB, LCP e budget di crawl. Un approfondimento incentrato sulla distribuzione: scelta di adapter-static/node/vercel/cloudflare/netlify, prerender = true/false/'auto', vincoli del runtime edge e creazione di sitemap.xml e robots.txt.

Prima pubblicazione: 3 lug 2026 · Ultimo aggiornamento: 3 ago 2026 · Advanced
Lingue

L'adapter di SvelteKit e l'impostazione del prerender per rotta decidono dove e quando una pagina viene renderizzata — HTML statico al momento della build, SSR su un server o SSR al edge — e questa decisione determina il TTFB, che influisce su LCP e capacità di crawl. Scegli adapter-static per siti puramente di contenuti, un adapter node/vercel/cloudflare con prerender per rotta per siti misti contenuti-plus-app, e un adapter edge quando il TTFB globale è importante (accettando cold start e nessun fs Node). prerender = 'auto' è lo strumento per siti misti. I runtime edge non possono leggere il filesystem. E SvelteKit non genera sitemap.xml o robots.txt — li costruisci come endpoint +server.js, con la strategia che dipende dal tuo adapter.

TL;DR — L’adapter non cambia cosa SvelteKit renderizza — cambia dove e quando: statico al build-time (adapter-static), al request-time su un server che gestisci tu (adapter-node), o al request-time su funzioni serverless/edge (adapter-vercel/-netlify/-cloudflare). prerender = true per rotta genera HTML statico e rimuove la rotta dal manifest dinamico; prerender = 'auto' pre-renderizza e la mantiene nel manifest — lo strumento per siti misti /blog/[slug]. I runtime edge girano su isolate V8: niente fs di Node, e i cold start penalizzano il TTFB, che alimenta l’LCP e (secondo il documento sul crawl budget di Google) la capacità di crawl. SvelteKit non genera nessun sitemap.xml o robots.txt — creali come endpoint +server.js, e nota che la strategia dipende dall’adapter. Questo è un companion più mirato e incentrato sul deployment rispetto all’articolo sui fondamenti SEO di SvelteKit in questa sezione; do per scontato che tu sappia già che SvelteKit è SSR-by-default e non tornerò su questo punto qui.

L’idea chiave che fa scattare tutto

L’adapter non cambia cosa viene renderizzato. Cambia dove e quando. Questo è tutto. I documenti di SvelteKit lo dicono con precisione: gli adapter “take the built app as input and generate output for 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 I tuoi componenti, le tue funzioni load, i tuoi metadati <svelte:head> — identici su ogni adapter. Ciò che cambia è:

  • Quando viene prodotto l’HTML: al build time (statico/pre-renderizzato) o al request time (SSR su un server, funzione serverless o funzione edge).
  • Dove viene prodotto: su un singolo server di origine, su una funzione serverless regionale, o su una rete edge vicina al visitatore.

Tutto ciò che segue è una conseguenza di questi due assi.

Perché le scelte di deployment sono scelte SEO

La catena è breve e ben documentata: TTFB → LCP → capacità di crawl.

Il time to first byte è quanto tempo impiega l’host per iniziare a inviare la risposta. Un file pre-renderizzato servito da una cache CDN ha un TTFB quasi pari a zero. Un server che deve renderizzare la pagina ne ha uno più alto. Una funzione serverless o edge con cold start può averne uno molto più alto al primo accesso. Il TTFB è un input diretto per il Largest Contentful Paint — non puoi dipingere ciò che non hai ricevuto — e l’LCP è un segnale Core Web Vitals.

Il lato crawl è dove Google è più esplicito. Dalla documentazione sul 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.” (traduzione) «Se il sito risponde rapidamente per un po’, il limite sale, il che significa che è possibile usare più connessioni per il crawl. Se il sito rallenta o risponde con errori del server, il limite scende e Google esegue meno crawl.» E la riga sulle best practice: “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.” (traduzione) «Rendi le tue pagine efficienti da caricare. Se Google può caricare e renderizzare le tue pagine più velocemente, potremmo essere in grado di leggere più contenuti dal tuo sito.» Una funzione edge con cold start che è lenta a rispondere è soggetta alla stessa dinamica di un server di origine lento.

Una nota di onestà fin dall’inizio: Google non pubblica alcuna guida specifica per SvelteKit. Non esiste un documento o un episodio di Search Off the Record che nomini gli adapter di SvelteKit, prerender = 'auto' o i cold start edge. Quello che sto facendo qui è applicare le linee guida generali di Google su rendering e crawl budget ai meccanismi specifici di SvelteKit — non citare un rappresentante che ha commentato SvelteKit, perché nessuno l’ha fatto. Il quadro di Google secondo cui “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” (traduzione) «il server-side o il pre-rendering è comunque un’ottima idea perché rende il tuo sito più veloce per utenti e crawler, e non tutti i bot possono eseguire JavaScript» è l’ancora ufficiale più vicina, ed è indipendente dal framework.

Scegliere un adapter per risultati SEO

adapter-auto — il default zero-config, e il suo limite

I nuovi progetti SvelteKit includono adapter-auto. Rileva la piattaforma — Vercel, Netlify, Cloudflare Pages, Azure, AWS — e installa l’adapter corrispondente al momento della build. È un buon punto di partenza, ma c’è un limite netto che vale la pena conoscere: adapter-auto non accetta opzioni. Nel momento in cui hai bisogno di { edge: true }, binding Cloudflare, ISR di Vercel o qualsiasi configurazione specifica della piattaforma, installi direttamente l’adapter sottostante (adapter-vercel, adapter-cloudflare, ecc.). Tratta auto come uno scaffold, non come una decisione di produzione.

adapter-static — SSG completo, per siti content-first

adapter-static prerenderizza l’intero sito in file statici al momento della build. Nessun server viene eseguito; un host serve HTML piatto. 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 Per un sito content-first questo è il profilo SEO più forte che puoi avere — TTFB più basso, nessun cold start, nulla che possa fallire. L’unico requisito è la trappola trattata ampiamente nell’articolo sui fondamenti: SSR deve rimanere attivo durante la build, altrimenti ottieni shell vuote invece di HTML renderizzato. Non lo rispiego qui oltre a segnalarlo.

Il problema è la rigidità. Qualsiasi cosa che richieda davvero logica server per richiesta (ricerca vera, contenuti per utente, gestione di form senza un endpoint di terze parti) non può vivere su una build puramente statica — che è esattamente a cosa servono i prossimi adapter.

adapter-node — un server che controlli tu

adapter-node produce un server Node.js autonomo. Lo esegui tu, lo ridimensioni tu, possiedi tu il TTFB. Questa è l’opzione più flessibile e quella con meno sorprese a runtime — API Node complete, incluso fs. È una buona scelta quando hai già infrastruttura, hai bisogno di librerie Node che i runtime edge non possono eseguire, o vuoi tempi di risposta prevedibili (senza cold start) da un server caldo. Il compromesso è operativo: stai eseguendo un server, e la sua velocità e disponibilità ora sono la tua capacità di crawling.

adapter-vercel — serverless, edge e ISR

adapter-vercel esegue il deploy sulle funzioni serverless di Vercel per default, con diverse leve rilevanti per la SEO impostate per rotta tramite export const config:

  • runtime: 'edge' sposta quella rotta al runtime edge di Vercel (più sotto).
  • regions controlla dove vengono eseguite le funzioni serverless — più vicine ai tuoi utenti (o al tuo database) significa latenza inferiore.
  • isr abilita la Rigenerazione Statica Incrementale: isr: { expiration: 60 } serve un asset statico in cache e lo rigenera dopo la finestra, dando “the performance and cost advantages of prerendered content with the flexibility of dynamically rendered content.” (traduzione) «i vantaggi in termini di prestazioni e costi dei contenuti prerenderizzati con la flessibilità dei contenuti renderizzati dinamicamente.» L’ISR è un vero e proprio quarto percorso tra puro statico e puro SSR — ma nota l’avvertenza della stessa documentazione: “Using ISR on a route with export const prerender = true will have no effect, since the route is prerendered at build time.” (traduzione) «Usare ISR su una rotta con export const prerender = true non avrà alcun effetto, poiché la rotta viene prerenderizzata al momento della build.» ISR e prerender sono alternative, non impilabili.

adapter-cloudflare — Workers/Pages, edge globale

adapter-cloudflare punta a Cloudflare Workers e Pages — SSR su una rete edge globale, spesso il TTFB più basso per un pubblico geograficamente distribuito. Il vincolo importante è il runtime: i Workers girano su isolate V8, non su Node. Dalla documentazione: “You can’t use fs in Cloudflare Workers.” (traduzione) «Non puoi usare fs in Cloudflare Workers.» Alcune API Node funzionano solo dietro il flag di compatibilità nodejs_compat, e anche in quel caso il supporto non è uno a uno. Se stavi leggendo file al momento della richiesta (una mappa di redirect, un file di dati, input per immagini OG personalizzate), quel codice richiede una ripensata — trattata nella sezione edge qui sotto.

(Il vecchio adapter-cloudflare-workers è deprecato; i nuovi progetti usano adapter-cloudflare, che gestisce sia Workers che Pages. Se sei su quello vecchio, migrare è il percorso consigliato.)

adapter-netlify — funzioni o Edge Functions (Deno)

adapter-netlify esegue il deploy sulle funzioni basate su Node di Netlify per impostazione predefinita, oppure su Edge Functions basate su Deno con edge: true. Stessa forma di Vercel: serverless predefinito con opt-in edge. Una nota specifica di SvelteKit: Netlify Forms richiede che la pagina del modulo sia prerenderizzata affinché Netlify possa rilevare il markup del modulo al momento del deploy, il che è un piccolo requisito “prerenderizza questa rotta” aggiunto alla scelta dell’adapter.

La decisione, in una riga ciascuna

  • Sito di solo contenutoadapter-static, prerenderizza tutto.
  • Sito di contenuto con aree dinamicheadapter-node/-vercel/-cloudflare, prerender = true sul contenuto, false/'auto' sulle rotte dinamiche.
  • App/dashboard con personalizzazione → SSR-first (node o edge), prerenderizza solo la shell statica (marketing, login).
  • Pubblico globale, sensibile al TTFB → un adapter edge per le rotte dinamiche, accettando i vincoli delle API Node e la realtà del cold-start.

(La scheda Decision Tree esplora questo come un flusso ramificato.)

Strategia di prerendering per siti misti

Cosa fanno realmente true / false / 'auto'

export const prerender è un’opzione di pagina per rotta (o per layout), e i tre valori non sono solo on/off:

  • true — costruisci questa rotta in HTML statico al momento della build. In modo critico, è “esclusa dai manifest usati per SSR dinamico, rendendo il tuo server (o le funzioni serverless/edge) più piccolo.” Una volta prerenderizzata, la rotta non può ripiegare sul rendering dinamico — è statica, punto e basta.
  • false — renderizza sempre su richiesta. Nessun file statico.
  • 'auto' — lo strumento per siti misti. Prerenderizza la rotta e la mantiene nel manifest del server dinamico, così la stessa rotta può essere servita staticamente per percorsi noti e renderizzata dal server per il resto. È costruito esattamente per il caso che i documenti descrivono: una rotta come /blog/[slug] “dove vuoi prerenderizzare i tuoi contenuti più recenti/popolari ma server-renderizzare la coda lunga.”

Poiché le rotte prerenderizzate riducono il bundle del server, un sito per lo più prerenderizzato con poche rotte 'auto'/false distribuisce una funzione più piccola, più economica e più veloce — un vantaggio di efficienza indipendente dalla SEO.

Le rotte dinamiche richiedono una funzione entries

Il crawler di prerendering scopre le pagine seguendo i link <a> dai tuoi punti di ingresso. Funziona per le rotte statiche, ma una rotta dinamica come /blog/[slug] non ha un URL fisso che il crawler possa trovare. Se nessun link punta a un dato slug, SvelteKit non saprà che esiste — e incontrerai il classico errore di build secondo cui le rotte “erano contrassegnate come prerenderizzabili, ma non sono state prerenderizzate.”

La soluzione è una funzione entries esplicita (o config.kit.prerender.entries) che enumera i valori dei parametri:

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

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

In pratica generi quella lista dal tuo CMS o dalla directory dei contenuti. Senza di essa, il prerendering copre solo gli slug che il crawler di link trova per caso.

Il pattern /blog/[slug] nel mondo reale

Metti insieme le due cose e hai la configurazione canonica per siti misti: prerender = 'auto' più una funzione entries che restituisce i tuoi post recenti e popolari. Quelli ottengono HTML statico al momento della build; tutto ciò che non è nella lista ricade su SSR su richiesta. I nuovi post vengono renderizzati dinamicamente fino alla build successiva che li prerenderizza. È il compromesso pragmatico tra “prerenderizza tutti i 40.000 post a ogni build” e “renderizza ogni post a ogni richiesta.”

Vincoli del runtime edge che influiscono sulla SEO

config.runtime = 'edge' è per rotta (su Vercel)

Edge non è un interruttore tutto-o-niente. Su Vercel è un’opzione di pagina per rotta:

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

Ciò significa che puoi spingere rotte ad alto traffico e memorizzabili nella cache verso l’edge per un TTFB basso mantenendo le rotte dipendenti da Node sul runtime serverless (Node) standard nello stesso deployment. Mescola deliberatamente.

Niente fs, niente API Node arbitrarie

I runtime edge — Cloudflare Workers, Vercel Edge Functions, Netlify’s Deno Edge Functions — non forniscono fs di Node. La documentazione di Cloudflare: “You can’t use fs in Cloudflare Workers.” Quella di Vercel: “You can’t use fs in edge functions.” Entrambe indicano le stesse due vie di fuga: usa l’helper read di $app/server per accedere agli asset inclusi nel bundle, oppure “prerender the routes in question” così che l’accesso ai file avvenga in fase di build invece che al momento della richiesta.

I casi legati alla SEO in cui questo è un problema: generazione dinamica di immagini OG che legge un file di font o un template, mappe di redirect basate su file, o un endpoint per la sitemap che legge contenuti dal disco. Ognuno di questi o passa a read() di $app/server o viene spostato in fase di prerender/build. Non è un blocco — è un vincolo “sapere prima di scegliere edge”.

Cold start e TTFB — quando edge aiuta e quando no

Le funzioni edge hanno comunque il cold start. Una funzione edge fredda alla prima richiesta può essere più lenta di un server Node caldo, e drammaticamente più lenta di un file prerenderizzato servito dalla cache. Edge vince quando la funzione rimane calda o quando è abbinata a una memorizzazione nella cache aggressiva così che la maggior parte delle richieste non raggiunga mai la funzione. Non è automaticamente l’opzione più veloce — “deploy sull’edge” non è sinonimo di “più veloce.” Per un sito di contenuti, l’output statico prerenderizzato batte la SSR edge sul TTFB ogni volta, perché non c’è nessuna funzione da avviare.

Generare sitemap.xml e robots.txt (SvelteKit non lo fa)

Questo è il vuoto che la maggior parte dei tutorial su SvelteKit salta e che la maggior parte degli audit rileva. SvelteKit genera nessun sitemap.xml e nessun robots.txt automaticamente — indipendentemente dall’adapter, indipendentemente da quante pagine prerenderizzi. Un sito completamente statico con migliaia di pagine prerenderizzate viene comunque pubblicato senza sitemap a meno che non ne crei una.

Il pattern dell’endpoint +server.js

La sitemap idiomatica è un endpoint di rotta che restituisce XML con il giusto Content-Type:

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

La strategia dipende dal tuo adapter

Ecco la parte che lega insieme tutto questo articolo: la tua strategia per la sitemap è a valle della scelta dell’adapter.

  • Su adapter-static, l’endpoint della sitemap ha bisogno di export const prerender = true così che sia incluso nell’output statico — non c’è un server a runtime per generarlo su richiesta. Viene creato in fase di build, il che significa che è fresco solo quanto la tua ultima build.
  • Su un adapter Node/serverless/edge, lo stesso endpoint può generare la sitemap dinamicamente per richiesta dal tuo CMS o database — sempre aggiornata, nessuna rebuild necessaria. (Su un adapter edge, ricorda il vincolo fs: prendi gli URL da un’API o da un binding, non da una lettura dal disco.)

Quindi la domanda “la mia sitemap dovrebbe essere statica o dinamica?” non è una decisione separata — deriva dall’adapter che hai già scelto.

robots.txt: file statico vs. endpoint

Due opzioni. Metti un semplice robots.txt nella tua cartella static/ (servito su /robots.txt automaticamente), che è la scelta più semplice e va bene per la maggior parte dei siti. Oppure generarlo da un endpoint src/routes/robots.txt/+server.js quando hai bisogno che cambi in base all’ambiente (bloccando i crawler in staging, permettendoli in produzione, per esempio). In ogni caso, non bloccare il tuo bundle /_app/ o i CSS — questo rompe il rendering per i motori che renderizzano.

Se arrivi da una prospettiva più ampia di framework o JavaScript-SEO, la logica “dove e quando avviene il rendering” qui è la stessa logica che governa la JavaScript SEO in generale, e il pezzo sui fondamenti di SvelteKit in questa sezione copre le modalità di rendering e i pattern di metadati su cui questo articolo si basa.

Add an expert note

Pin an expert quote

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