Guide SvelteKit Deployment SEO: Adapters, Prerendering, and Edge Rendering
SvelteKit's adapter and per-route prerender settings decide où and quand votre pages render — and que drives TTFB, LCP, and budget d’exploration. A deployment-focused deep dive: choosing adapter-static/node/vercel/cloudflare/netlify, prerender = vrai/faux/'auto', edge-runtime constraints, and building sitemap.xml and robots.txt.
Langues
SvelteKit's adapter and per-route prerender setting decide où and quand une page renders — static HTML at construire temps, SSR on a server, or SSR at the edge — and que decision drives TTFB, qui feeds LCP and explorer capacity. Pick adapter-static pour pure content sites, a node/vercel/cloudflare adapter with per-route prerender pour mixed content-plus-app sites, and an edge adapter quand global TTFB matters (accepting cold starts and aucun Node fs). prerender = 'auto' is the mixed-site outil. Edge runtimes can't lire the filesystem. And SvelteKit generates aucun sitemap.xml or robots.txt — vous construire ceux as +server.js endpoints, with the strategy selon votre adapter.
TL;DR — SvelteKit déjà renders votre pages on le serveur — que partie is handled. Ce page is à propos de the suivant decision: how votre site obtient construit and deployed. An adapter packages votre SvelteKit app pour a host (a static fichier host, a Node server, or a service comme Vercel or Cloudflare), and a per-page prerender setting decides si une page is turned into a plain HTML fichier ahead of temps or rendered fresh on every visit. Ceux two choices decide how fast robots d’exploration obtenir votre HTML — and SvelteKit won’t faire votre sitemap or robots.txt, so vous have to ajouter ceux yourself.
Ce que an adapter is (in plain terms)
Si you’ve déjà construit a SvelteKit site, vous know it sends réel HTML to the navigateur — le contenu is là avant quelconque JavaScript runs. Bon. That’s the hard SEO problem déjà solved (and si it isn’t solved pour vous yet, the SvelteKit fundamentals article in ce même section covers the rendering modes and the “empty shell” trap vous vouloir to éviter premier).
An adapter is the petit plugin que takes votre finished SvelteKit construire and turns it into something a spécifique host peut run. Evidence for this claim SvelteKit adapters transform a built application for deployment to a particular environment. Scope: SvelteKit adapters. Confidence: high · Verified: SvelteKit: Adapters Même site, différent package:
adapter-staticturns every page into a plain HTML fichier, construit une fois. Great pour a blog, docs, or a marketing site que doesn’t modifier per visitor.adapter-nodewraps votre app in a Node.js server vous run yourself.adapter-vercel,adapter-netlify,adapter-cloudflarepackage it pour ceux hosting services, qui render pages on demand — parfois on servers “at the edge,” physically fermer to votre visitors.
Le contenu is identical in tout cas. Ce que changements is quand the HTML is made (ahead of temps, or on chaque requête) and où (un server, or a global network).
Pourquoi ce is an SEO decision, pas simplement a tech un
The principal chose: speed. Une page that’s déjà a static fichier loads almost instantly. Une page que has to be construit on le serveur takes a moment. And Google has said plainly que si votre site “responds quickly pour a pendant que, the limite goes up, meaning plus connections peut be utilisé to explorer. Si le site slows bas… the limite goes bas and Google crawls moins.” So a slow deployment doesn’t simplement annoy utilisateurs — it peut mean Google reads moins of votre site.
The simple version of the decision
- A content site (blog, docs, marketing) → utiliser
adapter-staticand prerender everything. Fastest possible, nothing to break. - A content site with a few dynamic bits (search, comments) → utiliser a server
adapter (
node/vercel/cloudflare) and mark votre content pagesprerender = true, leaving the dynamic bits to render on requête. - An app or dashboard with logged-in, personalized pages → render on the server (SSR), prerender seulement the public marketing pages.
Don’t forget the two fichiers SvelteKit won’t faire pour vous
SvelteKit doesn’t generate a sitemap.xml or a robots.txt automatically. Vous
ajouter les yourself — usually as a petit endpoint fichier (sitemap.xml/+server.js)
and soit a fichier in votre static/ folder or un autre endpoint pour
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 It’s facile to forget parce que la plupart frameworks que render HTML pour
vous feel “complete.” Ces two aren’t.
Vouloir the deeper version — ce que chaque adapter fait to rendering, how
prerender = 'auto' handles a mixed site, pourquoi edge functions can’t lire fichiers,
and how le sitemap strategy changements with votre adapter? Switch to the
Avancé tab.
TL;DR — The adapter doesn’t modifier ce que SvelteKit renders — it changements où and quand: build-time static (
adapter-static), request-time on a server vous run (adapter-node), or request-time on serverless/edge functions (adapter-vercel/-netlify/-cloudflare). Per-routeprerender = truebuilds static HTML and drops the route from the dynamic manifest;prerender = 'auto'prerenders and garde it in the manifest — the outil pour mixed/blog/[slug]sites. Edge runtimes run on V8 isolates: aucun Nodefs, and cold starts hurt TTFB, qui feeds LCP and (per Google’s crawl-budget doc) explorer capacity. SvelteKit generates aucun sitemap.xml or robots.txt — construire les as+server.jsendpoints, and remarque the strategy dépend on the adapter. Ce is a narrower, deployment-focused companion to the SvelteKit SEO fundamentals article in ce section; I assume vous déjà know SvelteKit is SSR-by-default and won’t re-litigate que ici.
The un idea que rend tout of ce click
The adapter fait pas modifier ce que renders. It changements où and quand.
That’s the whole chose. The SvelteKit docs put it precisely: adapters “prendre the
construit app as input and generate output pour 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 Votre components, votre
load functions, votre <svelte:head> metadata — identical à travers every adapter.
Ce que differs is:
- Quand the HTML is produced: at construire temps (static/prerendered) or at requête temps (SSR on a server, serverless function, or edge function).
- Où it’s produced: on a unique origin server, on a regional serverless function, or on an edge network fermer to the visitor.
Everything ci-dessous is a consequence of ceux two axes.
Pourquoi deployment choices are SEO choices
The chain is short and well-documented: TTFB → LCP → explorer capacity.
Temps to premier byte is how long the host takes to commencer sending la réponse. A prerendered fichier served from a CDN cache has a near-zero TTFB. A server que has to render lune page has a plus élevé un. A cold-starting serverless or edge function peut have a beaucoup plus élevé un on the premier hit. TTFB is a direct input to Largest Contentful Paint — vous pouvez’t paint ce que vous haven’t reçu — and LCP is a Core Web Vitals signal.
The explorer side is où Google is la plupart explicit. From the crawl-budget documentation: “Si le site responds quickly pour a pendant que, the limite goes up, meaning plus connections peut be utilisé to explorer. Si le site slows bas or responds with server errors, the limite goes bas and Google crawls moins.” And the best-practice line: “Faire votre pages efficient to charger. Si Google peut charger and render votre pages faster, we pourrait be able to En savoir plus content from votre site.” A cold-starting edge function that’s slow to respond is subject to the même dynamic as a slow origin server.
Un honesty remarque up front: Google publishes aucun SvelteKit-specific guidance.
There’s aucun doc or Search Off the Record episode naming SvelteKit adapters,
prerender = 'auto', or edge cold starts. Ce que I’m doing ici is applying
Google’s general rendering and crawl-budget guidance to SvelteKit’s spécifique
mechanics — pas quoting a rep who commented on SvelteKit, parce que none has. The
Google framing que “server-side or pre-rendering is encore a great idea parce que
it rend votre website faster pour utilisateurs and robots d’exploration, and pas tout bots peut run
JavaScript” is the closest official anchor, and it’s framework-agnostic.
Choosing an adapter pour le SEO outcomes
adapter-auto — the zero-config par défaut, and its ceiling
Nouveau SvelteKit projects ship with adapter-auto. It detects the platform —
Vercel, Netlify, Cloudflare Pages, Azure, AWS — and installs the matching adapter
at construire temps. It’s a fine starting point, but there’s a hard ceiling worth
knowing: adapter-auto ne fait pas prendre quelconque options. The moment vous besoin
{ edge: true }, Cloudflare bindings, Vercel ISR, or quelconque platform-specific
configuration, vous install the underlying adapter (adapter-vercel,
adapter-cloudflare, etc.) directement. Treat auto as a scaffold, pas a production
decision.
adapter-static — complet SSG, pour content-first sites
adapter-static prerenders votre whole site to static fichiers at construire temps. Aucun
server runs; a host sert flat HTML. 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 Pour a content-first site ce is the
strongest SEO profile vous pouvez have — lowest TTFB, aucun cold starts, nothing to fall
over. The un requirement is the trap covered at length in the fundamentals
article: SSR doit stay on during the construire, or vous obtenir vide shells au lieu de
rendered HTML. I won’t re-explain que ici au-delà flagging it.
The catch is rigidity. Anything que genuinely nécessite server logic per requête (vrai search, per-user content, formulaire handling sans a third-party endpoint) can’t live on a purely static construire — qui is exactly ce que the suivant adapters are pour.
adapter-node — a server vous contrôler
adapter-node produces a standalone Node.js server. Vous run it, vous scale it, vous
propre the TTFB. Ce is the la plupart flexible option and the un with the fewest runtime
surprises — complet Node APIs, notamment fs. It’s a bon fit quand vous have
infrastructure déjà, besoin Node libraries que edge runtimes can’t run, or vouloir
predictable (non-cold-starting) réponse times from a warm server. The tradeoff is
operational: you’re running a server, and its speed and uptime are now votre explorer
capacity.
adapter-vercel — serverless, edge, and ISR
adapter-vercel deploys to Vercel’s serverless functions by par défaut, with several
SEO-relevant levers définir per route via export const config:
runtime: 'edge'moves que route to Vercel’s edge runtime (plus ci-dessous).regionscontrôle où serverless functions run — closer to votre utilisateurs (or votre database) signifie lower latency.isrenables Incremental Static Regeneration:isr: { expiration: 60 }sert a mis en cache static asset and regenerates it après the window, giving “the performances and cost advantages of prerendered content with the flexibility of dynamically rendered content.” ISR is a genuine fourth chemin entre pure-static and pure-SSR — but remarque the docs’ propre caveat: “En utilisant ISR on a route withexport const prerender = trueva have aucun effect, since the route is prerendered at construire temps.” ISR and prerender are alternatives, pas stackable.
adapter-cloudflare — Workers/Pages, global edge
adapter-cloudflare targets Cloudflare Workers and Pages — SSR on a global edge
network, souvent the lowest TTFB pour a geographically spread audience. The important
constraint is the runtime: Workers run on V8 isolates, pas Node. From the docs:
“You can’t use fs in Cloudflare Workers.” Some Node APIs fonctionner seulement behind the
nodejs_compat compatibility flag, and même alors prise en charge isn’t one-to-one. Si vous
were reading fichiers at requête temps (a redirection map, a données fichier, custom OG-image
inputs), que code nécessite a rethink — covered in the edge section ci-dessous.
(The older adapter-cloudflare-workers is deprecated; nouveau projects utiliser
adapter-cloudflare, qui handles les deux Workers and Pages. Si you’re on the old
un, migrating is the recommended chemin.)
adapter-netlify — functions or Edge Functions (Deno)
adapter-netlify deploys to Netlify’s Node-based functions by par défaut, or to
Deno-based Edge Functions with edge: true. Même shape as Vercel: par défaut
serverless with an edge opt-in. Un SvelteKit-specific footnote — Netlify Formulaires
exiger the form’s page to be prerendered so Netlify peut detect the formulaire markup
at deploy temps, qui is a petit “prerender this route” requirement layered on top
of the adapter choice.
La décision en une ligne chaque
- Pure content site →
adapter-static, prerender everything. - Content site with dynamic pockets →
adapter-node/-vercel/-cloudflare,prerender = trueon content,false/'auto'on the dynamic routes. - App/dashboard with personalization → SSR-first (node or edge), prerender seulement the static shell (marketing, login).
- Global, TTFB-critical audience → an edge adapter pour the dynamic routes, accepting the Node-API constraints and cold-start reality.
(The Decision Tree tab walks ce as a branching flow.)
Prerendering strategy pour mixed sites
Ce que true / false / 'auto' en réalité do
export const prerender is a per-route (or per-layout) page option, and the three
valeurs aren’t simplement on/off:
true— construire ce route to static HTML at construire temps. Critically, it’s “excluded from manifests utilisé pour dynamic SSR, making votre serveur (or serverless/edge functions) plus petit.” Une fois prerendered, the route can’t fall back to dynamic rendering — it’s static, complet arrêter.false— toujours render on requête. Aucun static fichier.'auto'— the mixed-site outil. It prerenders the route and garde it in the dynamic server manifest, so the même route peut be served statically pour connu paths and server-rendered pour the rest. Ce is construit pour exactly the cas the docs décrire: a route comme/blog/[slug]“où vous vouloir to prerender votre la plupart recent/popular content but server-render the long tail.”
Parce que prerendered routes shrink le serveur bundle, a mostly-prerendered site
with a few 'auto'/false routes deploys a plus petit, cheaper, faster function —
an efficiency win independent of SEO.
Dynamic routes besoin an entries function
The prerender robot d’exploration discovers pages by suivant <a> liens from votre entry
points. Que fonctionne pour static routes, but a dynamic route comme /blog/[slug] has
aucun fixed URL pour the robot d’exploration to trouver. Si nothing liens to a donné slug, SvelteKit
won’t know it exists — and you’ll hit the classic construire error que routes “were
marked as prerenderable, but were pas prerendered.”
The fix is an explicit entries function (or config.kit.prerender.entries) que
enumerates the parameter valeurs:
// src/routes/blog/[slug]/+page.server.js
export const prerender = true;
export function entries() {
return [
{ slug: 'hello-world' },
{ slug: 'sveltekit-deployment-seo' },
];
}En pratique vous generate que liste from votre CMS or content directory. Sans it, prerendering seulement covers the slugs the lien robot d’exploration se produit to trouver.
The /blog/[slug] pattern in the wild
Put the two ensemble and vous have the canonical mixed-site setup: prerender = 'auto' plus an entries function que renvoie votre recent and popular posts.
Ceux obtenir static HTML at construire temps; anything pas in the liste falls via to SSR
on demand. Nouveau posts render dynamically jusqu’à the suivant construire prerenders les. It’s
the pragmatic middle ground entre “prerender all 40,000 posts every build” and
“render every post on every request.”
Edge runtime constraints que affecter SEO
config.runtime = 'edge' is per-route (on Vercel)
Edge isn’t an all-or-nothing switch. On Vercel it’s a per-route page option:
// +page.server.js or +server.js
export const config = { runtime: 'edge' };Que signifie vous pouvez push high-traffic, cacheable routes to the edge pour low TTFB pendant que keeping Node-dependent routes on the standard serverless (Node) runtime in the même deployment. Mix deliberately.
Aucun fs, aucun arbitrary Node APIs
The edge runtimes — Cloudflare Workers, Vercel Edge Functions, Netlify’s Deno Edge
Functions — don’t provide Node’s fs. Cloudflare’s docs: “Vous pouvez’t utiliser fs in
Cloudflare Workers.” Vercel’s: “Vous pouvez’t utiliser fs in edge functions.” Les deux point
to the même two escape hatches: utiliser the read helper from $app/server to accès
bundled assets, or “prerender the routes in question” so the fichier accès se produit
at construire temps au lieu de at requête temps.
The SEO-adjacent cas où ce bites: dynamic OG-image generation que reads a
font or template fichier, file-based redirection maps, or a sitemap endpoint que reads
content off disk. Quelconque of ceux soit moves to $app/server’s read() or moves to
prerender/construire temps. It’s pas a blocker — it’s a “know before you pick edge”
constraint.
Cold starts and TTFB — quand edge helps and quand it doesn’t
Edge functions encore cold-start. A cold edge function on its premier requête peut be slower que a warm Node server, and dramatically slower que a prerendered fichier served from cache. Edge wins quand the function stays warm or quand it’s paired with aggressive mise en cache so la plupart requêtes jamais hit the function at tout. It is pas automatically the fastest option — “deploy to the edge” n’est pas a synonym pour “faster.” Pour a content site, prerendered static output beats edge SSR on TTFB every temps, parce que there’s aucun function to commencer.
Generating sitemap.xml and robots.txt (SvelteKit won’t)
Ce is the gap la plupart SvelteKit tutorials skip and la plupart audits catch. SvelteKit generates aucun sitemap.xml and aucun robots.txt automatically — regardless of adapter, regardless of how nombreux pages vous prerender. A entièrement static site with thousands of prerendered pages encore ships with aucun sitemap unless vous construire un.
The +server.js endpoint pattern
The idiomatic sitemap is a route endpoint que renvoie XML with the correct
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' },
});
}The strategy dépend on votre adapter
Here’s the partie que ties ce whole article ensemble: votre sitemap strategy is downstream of votre adapter choice.
- On
adapter-static, le sitemap endpoint nécessiteexport const prerender = vraiso it’s inclus in the static output — there’s aucun server at runtime to generate it on requête. It’s baked at construire temps, qui signifie it’s seulement as fresh as votre dernier construire. - On a Node/serverless/edge adapter, the même endpoint peut generate le sitemap
dynamically per requête from votre CMS or database — toujours current, aucun rebuild
nécessaire. (On an edge adapter, remember the
fsconstraint: pull URLs from an API or binding, pas a disk lire.)
So the “should my sitemap be static or dynamic?” question isn’t a separate decision — it falls out of the adapter vous déjà chose.
robots.txt: static fichier vs. endpoint
Two options. Drop a plain robots.txt in votre static/ folder (served at
/robots.txt automatically), qui is the simplest choice and fine pour la plupart sites.
Or generate it from a src/routes/robots.txt/+server.js endpoint quand vous besoin it
to differ by environment (blocking robots d’exploration on staging, allowing les in
production, pour instance). Soit façon, don’t block votre /_app/ bundle or CSS —
que breaks rendering pour engines que do render.
Si you’re coming at ce from the broader framework or JavaScript-SEO angle, the “where and when does rendering happen” logic ici is the même logic que governs JavaScript SEO généralement, and the SvelteKit fundamentals piece in ce section covers the rendering modes and metadata patterns ce article builds on top of.
AI summary
A condensed prendre on the Avancé version:
- The adapter changements où and quand, pas ce que. Adapters “prendre the construit app as input and generate output pour deployment” — même content, différent timing (construire vs. requête temps) and emplacement (origin vs. edge).
- Pourquoi it’s an SEO decision: TTFB → LCP → explorer capacity. Google: si a site “responds quickly… the limite goes up… Si le site slows bas… Google crawls moins.” Aucun Google guidance noms SvelteKit specifically — ce is general guidance applied to SvelteKit mechanics.
- Adapters:
adapter-auto(zero-config, aucun options);adapter-static(SSG, content sites, lowest TTFB);adapter-node(server vous contrôler, complet Node APIs);adapter-vercel(serverless + edge + ISR);adapter-cloudflare(global edge Workers, aucunfs;adapter-cloudflare-workersis deprecated);adapter-netlify(functions or Deno Edge Functions). - Prerender:
truebuilds static HTML and removes the route from the dynamic manifest;falsetoujours SSRs;'auto'prerenders and garde it dynamic — the mixed-site outil pour/blog/[slug](prerender popular, SSR the long tail). - Dynamic routes besoin an
entriesfunction or vous hit the “marked as prerenderable, but were pas prerendered” error. - Edge constraints:
runtime: 'edge'is per-route (Vercel); aucunfs(“You can’t use fs in Cloudflare Workers” / edge functions) — utiliser$app/server’sread()or prerender; cold starts peut faire edge slower que a warm server or static fichier. - Aucun built-in sitemap/robots.txt. Construire a
sitemap.xml/+server.jsendpoint (prerender = trueonadapter-static; dynamic on server/edge adapters). robots.txt viastatic/or an endpoint. - ISR ≠ prerender-plus: “En utilisant ISR on a route with
export const prerender = vraiva have aucun effect.” They’re alternatives.
Documentation officielle
Primary-source documentation from SvelteKit and the moteur de recherches.
SvelteKit
- Adapters • SvelteKit Docs — the overview: adapters prendre the construit app and generate deployment output.
- Zero-config deployments (adapter-auto) • SvelteKit Docs — per-platform detection and the “does not take any options” limitation.
- Node servers (adapter-node) • SvelteKit Docs — the standalone Node server, environment variables, graceful shutdown.
- Static site generation (adapter-static) • SvelteKit Docs — full-site SSG, the SSR requirement, and the SPA-fallback SEO warning.
- Vercel (adapter-vercel) • SvelteKit Docs — per-route
runtime,regions,split, and Incremental Static Regeneration. - Cloudflare (adapter-cloudflare) • SvelteKit Docs — Workers/Pages,
platform.envbindings,nodejs_compat, and thefslimitation. - Cloudflare Workers (adapter-cloudflare-workers, deprecated) • SvelteKit Docs — the deprecated legacy adapter and migration chemin.
- Netlify (adapter-netlify) • SvelteKit Docs — Node Functions vs. Deno-based Edge Functions (
edge: true), and the Formulaires prerender requirement. - Page options (prerender, ssr, csr, config) • SvelteKit Docs —
prerender = true/false/'auto', theentriesfunction, and per-routeconfignotammentruntime: 'edge'.
- Comprendre JavaScript SEO Basics — the render queue and “not all bots can run JavaScript.”
- Optimize votre budget d’exploration — explorer capacity tied to réponse speed; “make your pages efficient to load.”
Bing / Microsoft
- bingbot Series: JavaScript, Dynamic Rendering, and Cloaking. Oh My! — Bing’s prerendering/dynamic-rendering recommendation and the cloaking clarification.
- Fast Front-End Performances pour Microsoft Bing — Bing’s propre SSR + CDN/edge-node architecture as a real-world proof point.
Quotes from the source
On-the-record statements from the SvelteKit docs, Google, and Bing. Chaque lien is a deep lien que jumps to the quoted passage on the source page.
SvelteKit docs — adapters & page options
- “adapter-auto does not take any options.” — on the zero-config par défaut adapter. Jump to quote
- On
prerender = true— prerendered routes are “excluded from manifests used for dynamic SSR, making your server (or serverless/edge functions) smaller.” Jump to quote - On
'auto'— the/blog/[slug]cas où vous vouloir to “prerender your most recent/popular content but server-render the long tail.” Jump to quote - On the edge
fslimitation — “You can’t use fs in Cloudflare Workers.” Jump to quote - On Vercel ISR vs. prerender — “Using ISR on a route with export const prerender = true will have no effect, since the route is prerendered at build time.” Jump to quote
Google — rendering & budget d’exploration
- “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.” Jump to quote
- “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.” Jump to quote
- “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.” Jump to quote
Bing — prerendering & its propre edge architecture
- “We encourage detecting our bingbot user agent, prerendering the content on the server side and outputting static HTML for such sites…” — Fabrice Canel & Frédéric Dubut, Microsoft Bing. Jump to quote
- “User traffic routes first to the closest CDN node (called an ‘edge node’).” — Bing Search Quality Insights, on Bing’s propre SSR + edge architecture. Jump to quote
SvelteKit deployment SEO checklist
A réussir to confirmer votre adapter, prerender, and sitemap setup won’t hurt robots d’exploration:
- You’ve déplacé off
adapter-autoto an explicit adapter si vous besoin quelconque configuration (edge, ISR, bindings). - The adapter matches le site type —
adapter-staticpour pure content, a server/edge adapter pour anything with per-request logic. - Content routes are
prerender = true(or'auto'); seulement genuinely dynamic routes are left to SSR. - Mixed dynamic routes (
/blog/[slug]) utiliserprerender = 'auto'with anentriesfunction enumerating connu paths. - Aucun unresolved “marked as prerenderable, but were not prerendered” construire errors.
- Si quelconque route uses
runtime: 'edge', it fait pas appel Nodefs— fichier accès uses$app/server’sread()or is prerendered. - You’ve accounted pour cold starts on edge/serverless — cacheable, static, or warm où TTFB matters.
- A sitemap.xml endpoint exists (
prerender = trueonadapter-static; dynamic on server/edge adapters). - A robots.txt exists (in
static/or as a+server.jsendpoint) and fait pas block/_app/or CSS. - Vous are pas trying to stack ISR on a
prerender = trueroute (it has aucun effect). - Vous verified the rendered HTML and réponse speed in GSC Inspection d’URL and PageSpeed Insights.
The mental models
1. Où and quand, pas ce que. The adapter jamais changements votre content — it changements quand the HTML is made (construire temps vs. requête temps) and où (origin vs. edge). Every deployment SEO question reduces to ceux two axes. Demander les avant vous touch config.
2. Prerender removes a route from le serveur.
prerender = true isn’t simplement “make it static” — it takes the route out of the
dynamic manifest. Que shrinks votre function and rules out a dynamic fallback.
'auto' is the exception: prerendered and encore in the manifest.
3. The /blog/[slug] split.
The par défaut pattern pour contenu réel sites: prerender the entries vous pouvez nom
(entries function renvoie recent/popular), SSR the long tail. 'auto' is the
switch que rend les deux vrai at une fois.
4. Edge is a trade, pas an upgrade.
Edge buys vous geographic proximity (low TTFB quand warm) and costs vous Node APIs
(aucun fs) and cold-start risk. It beats a warm Node server seulement parfois, and
loses to prerendered static output on TTFB toujours. Choisir it pour a raison, pas by
par défaut.
5. Le sitemap follows the adapter.
“Static or dynamic sitemap?” isn’t a separate decision. adapter-static →
prerendered sitemap, fresh seulement at construire. Server/edge adapter → per-request
sitemap, toujours current. The adapter déjà answered the question.
6. Nothing generates the two fichiers. SvelteKit rend aucun sitemap.xml and aucun robots.txt, pour quelconque adapter. Si vous didn’t écrire les, ils don’t exist. Bake ce into votre launch checklist.
Qui adapter + prerender combo devrait I pick?
The core “which path do I take?” question in SvelteKit deployment is how devrait ce site ship? Walk votre site via ce:
1. Fait quelconque page besoin per-request server logic — auth, personalization, live search, formulaire handling, per-user données? → Aucun (every page is the même pour every visitor): go to 2. → Yes: skip to 3.
2. Pure content site (blog, docs, marketing).
→ Utiliser adapter-static, définir prerender = true site-wide (or in the root
layout). Ajouter a prerendered sitemap.xml/+server.js (prerender = true) and a
static/robots.txt. Lowest TTFB, aucun cold starts, nothing to run. Arrêter ici.
3. Is the whole site dynamic, or simplement some routes? → Simplement some routes (mostly content, a few dynamic bits): go to 4. → Mostly/entirely dynamic (app, dashboard, ecommerce with per-user données): go to 5.
4. Content site with dynamic pockets.
→ Utiliser a server/edge adapter (adapter-node, -vercel, or
-cloudflare). Mark content routes prerender = true, dynamic routes
false. Pour /blog/[slug]-style routes with known-popular content, utiliser
prerender = 'auto' + an entries function. Generate le sitemap dynamically
from votre CMS. Fait.
5. App / dashboard / ecommerce (SSR-first). Now pick où SSR runs:
→ Predictable latency, Node libraries, vous have infra: adapter-node
(warm server, complet Node APIs, aucun cold-start surprises).
→ Global audience, TTFB matters la plupart, aucun heavy Node deps: an edge adapter
(adapter-cloudflare, or adapter-vercel with runtime: 'edge' per route) —
accept aucun fs (utiliser $app/server’s read() or prerender) and cold starts.
Prerender seulement the truly static shell (marketing, login).
Fourth chemin (Vercel seulement): si a route is “mostly static but occasionally
changements,” considérer ISR (isr: { expiration }) au lieu de prerender = true
— jamais les deux, since “ISR on a route with export const prerender = vrai va have
aucun effect.”
Devrait my sitemap be static or dynamic?
On adapter-static? → Static/prerendered sitemap endpoint
(prerender = true). It’s baked at construire; fine pour sites que rebuild on publish.
On a Node/serverless/edge adapter? → Dynamic sitemap generated per requête
from votre CMS/DB — toujours current, aucun rebuild. (On edge, pull URLs from an API or
binding, pas a disk fs lire.)
Jamais: ship aucun sitemap parce que “the pages are all static.” Static output and sitemap discoverability are unrelated — SvelteKit generates neither fichier pour quelconque adapter.
SvelteKit deployment SEO — cheat sheet
Adapters En un coup d’œil
| Adapter | Renders | Runtime | SEO remarque |
|---|---|---|---|
adapter-static | Construire temps (SSG) | none | Lowest TTFB, aucun cold starts; content sites |
adapter-node | Requête temps (SSR) | Node | Complet Node APIs (fs ✅); vous run le serveur |
adapter-vercel | Requête temps | serverless / edge | Per-route runtime, regions, ISR |
adapter-cloudflare | Requête temps | V8 edge | Global edge; aucun fs; nodejs_compat |
adapter-netlify | Requête temps | Node / Deno edge | edge: true pour Deno Edge Functions |
adapter-auto | (detects ci-dessus) | — | Takes aucun options — scaffold seulement |
Prerender valeurs
| Valeur | Static HTML? | In dynamic manifest? | Utiliser pour |
|---|---|---|---|
true | ✅ | ❌ (supprimé) | Connu static content routes |
false | ❌ | ✅ | Genuinely dynamic routes |
'auto' | ✅ | ✅ | /blog/[slug] — prerender popular, SSR long tail |
Fast rules
- Dynamic prerendered routes → ajouter an
entriesfunction (or hit the “not prerendered” error). runtime: 'edge'is per-route (Vercel) — mix edge and Node routes.- Edge = aucun
fs→ utiliser$app/server’sread()or prerender. - Cold starts faire edge slower que a warm server / static fichier on premier hit.
- ISR ≠ prerender —
isron aprerender = trueroute ne fait pashing. - Aucun auto sitemap/robots.txt — construire les deux.
prerender = trueon le sitemap endpoint pouradapter-static; dynamic on server/edge. - Jamais block
/_app/or CSS in robots.txt.
A prerendered route is manquant from the deployment
Probable causer: the robot d’exploration pourrait pas découvrir the chemin, an entries valeur is absent, or prerendering failed. Fix: ajouter crawlable liens or explicit entries and treat construire warnings as release échecs. Confirmer: the output manifest contient the route and production renvoie complet HTML.
adapter-static fails on a dynamic route
Probable causer: the route ne peut pas be entièrement enumerated at construire temps. Fix: supply finite entries, redesign the route, or utiliser a server-capable adapter pour que chemin. Confirmer: the selected adapter builds and every representative route renvoie the intended réponse.
Edge deployment throws filesystem or Node API errors
Probable causer: route code or a dependency assumes Node fonctionnalités unavailable in the edge runtime. Fix: replace the dependency, déplacer the fonctionner to a compatible service, or choisir a Node adapter. Confirmer: production SSR succeeds sans runtime exceptions.
Sitemap or robots.txt renvoie HTML
Probable causer: a fallback route catches the endpoint or the +server handler sets the incorrect corps/headers. Fix: créer explicit endpoint handlers with correct content types. Confirmer: direct requêtes retourner the attendu text/XML réponse and 200 status.
Metadata differs entre prerendered and SSR routes
Probable causer: head données is chargé in différent code paths or dépend on navigateur state. Fix: centralize metadata generation from server/build-safe page données. Confirmer: raw HTML pour les deux route types contient equivalent title, canonical, and robots logic.
Confirmer ce que votre adapter en réalité shipped
The point of picking an adapter and prerendering is que a robot d’exploration obtient fast, complet HTML. Ces checks confirmer that’s ce que en réalité happened — from the raw réponse, pas le navigateur.
Is lune page prerendered/SSR’d (content in raw HTML)?
A plain curl runs aucun JavaScript, so it sees exactly ce que a non-rendering robot d’exploration
sees.
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"Is TTFB fast (or is a function cold-starting)?
TTFB feeds LCP and explorer capacity, so mesurer it. Hit l’URL cold, alors warm:
# 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/"
doneA prerendered/static page devrait be consistently low. A grand premier valeur que drops on the second hit is a classic serverless/edge cold commencer.
Was ce route prerendered or served dynamically?
Static hosts and CDNs usually reveal it in headers (cache status, age,
x-vercel-cache, cf-cache-status):
curl -sI "https://example.com/your-page/" | grep -iE "cache|age|x-vercel|cf-"A HIT (or a nonzero age) signifie you’re being served mis en cache/prerendered content;
a MISS/DYNAMIC on every requête signifie it’s rendering per requête.
Fait le sitemap en réalité exist and retourner XML?
Since SvelteKit doesn’t generate un, vérifier yours is really là with the correct content type:
curl -sI "https://example.com/sitemap.xml" | grep -iE "HTTP/|content-type"
# Want: 200 + content-type: application/xml (not text/html or a 404)DevTools console one-liner
Paste in le navigateur console to comparer rendered DOM contre ce que a robot d’exploration nécessite —
si votre headline is ici but manquant from the curl output ci-dessus, it’s
client-rendered:
// 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')));Vérifier robots.txt isn’t blocking the bundle
curl -sL "https://example.com/robots.txt" | grep -iE "disallow.*(/_app|\.js|\.css)"A Disallow matching /_app/ (SvelteKit’s bundled output) or votre CSS signifie
engines can’t render lune page — almost toujours a mistake.
Outils pour debugging SvelteKit deployment SEO
- Inspection d’URL (Recherche Google Console) — the source of truth. Live-test une URL and vérifier the rendered HTML, screenshot, and page resources to confirmer content and metadata are présent and nothing is blocked.
- PageSpeed Insights — the SvelteKit docs’ propre recommended outil; surfaces TTFB and the Core Web Vitals (LCP/INP/CLS) que votre adapter choice la plupart affecte.
- WebPageTest — waterfall + filmstrip pour diagnosing TTFB and cold-start timing on edge/serverless deploys.
curl -w "%{time_starttransfer}"— the quickest raw TTFB and cold-start vérifier (voir the Scripts tab).- Host dashboards (Vercel / Cloudflare / Netlify Analytics) — function invocation counts, cold-start rates, and cache-hit ratios per route — the ground truth pour si edge/serverless is en réalité fast pour vous.
- Screaming Frog SEO Spider — explorer with JS rendering on/off to diff raw vs. rendered HTML à travers le site and confirmer prerendered routes are complet.
- Ahrefs Site Audit — surfaces manquant/blocked sitemaps, chaîne de redirectionss, broken canonicals, and indexability problèmes at scale.
Testez vos connaissances: SvelteKit Deployment SEO
Five rapide questions on adapters, prerendering, and edge rendering in SvelteKit. Pick an réponse pour chaque, alors vérifier.
Ressources utiles
My connexe writing
- JavaScript SEO: A Definitive Guide — my complet référence on rendering modes (SSR, static rendering, prerendering, and the CSR pitfalls) que underpin every adapter decision ici. As I put it là, quelconque kind of SSR, static rendering, or prerendering setup is going to be fine pour moteur de recherches — qui is exactly the safety net behind ces adapter choices.
- The Beginner’s Guide to SEO technique — où rendering, exploration, and Core Web Vitals fit in the bigger picture.
My speaking
- How Search Fonctionne (SlideShare) — my walkthrough of exploration, rendering, indexation, and ranking, qui is the backdrop pour pourquoi TTFB and rendering timing matter. (My standing disclaimer s’applique: “This is my understanding of systems… not going to be 100% complete or accurate.”)
From autour the industry
- Adapters • SvelteKit Docs — the authoritative overview of every official adapter and how they’re specified in
svelte.config.js. - Page options (prerender, ssr, csr, config) • SvelteKit Docs — the per-route
prerendervaleurs, theentriesfunction, and per-routeconfignotammentruntime: 'edge', in the team’s propre words. - Vercel (adapter-vercel) • SvelteKit Docs — the edge runtime, regions, and the ISR-vs-prerender caveat.
- Cloudflare (adapter-cloudflare) • SvelteKit Docs — Workers/Pages deployment, bindings, and the
fslimitation. - SvelteKit • Cloudflare Pages docs — the deployment mechanics and
platformbindings from Cloudflare’s side. - SvelteKit SEO: Votre Secret Weapon (Okupter) — a practitioner guide to prerendering, meta tags, and the
+server.jssitemap/RSS pattern. - A Deep Dive into SvelteKit’s Rendering Techniques (Ce Dot Labs) — SSR/SSG/CSR mechanics and per-route/per-layout config, with the “SSR can be expensive” server-load tradeoff.
- Comprendre JavaScript SEO Basics (Recherche Google Central) — the render queue and “not all bots can run JavaScript,” the general guidance every adapter choice sits sous.