SvelteKit Deployment SEO: Adapters, Prerendering, and Edge Rendering
SvelteKit's adapter and per-route prerender settings decide where and when your pages render — and that drives TTFB, LCP, and crawl budget. A deployment-focused deep dive: choosing adapter-static/node/vercel/cloudflare/netlify, prerender = true/false/'auto', edge-runtime constraints, and building sitemap.xml and robots.txt.
SvelteKit's adapter and per-route prerender setting decide where and when a page renders — static HTML at build time, SSR on a server, or SSR at the edge — and that decision drives TTFB, which feeds LCP and crawl capacity. Pick adapter-static for pure content sites, a node/vercel/cloudflare adapter with per-route prerender for mixed content-plus-app sites, and an edge adapter when global TTFB matters (accepting cold starts and no Node fs). prerender = 'auto' is the mixed-site tool. Edge runtimes can't read the filesystem. And SvelteKit generates no sitemap.xml or robots.txt — you build those as +server.js endpoints, with the strategy depending on your adapter.
TL;DR — SvelteKit already renders your pages on the server — that part is handled. This page is about the next decision: how your site gets built and deployed. An adapter packages your SvelteKit app for a host (a static file host, a Node server, or a service like Vercel or Cloudflare), and a per-page prerenderThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal. setting decides whether a page is turned into a plain HTML file ahead of time or rendered fresh on every visit. Those two choices decide how fast crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. get your HTML — and SvelteKit won’t make your sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. or robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere., so you have to add those yourself.
What an adapter is (in plain terms)
If you’ve already built a SvelteKit site, you know it sends real HTML to the browser — the content is there before any JavaScript runs. Good. That’s the hard SEO problem already solved (and if it isn’t solved for you yet, the SvelteKit fundamentals article in this same section covers the renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. modes and the “empty shell” trap you want to avoid first).
An adapter is the small plugin that takes your finished SvelteKit build and turns it into something a specific host can 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 Same site, different package:
adapter-staticturns every page into a plain HTML file, built once. Great for a blog, docs, or a marketing site that doesn’t change per visitor.adapter-nodewraps your app in a Node.js server you run yourself.adapter-vercel,adapter-netlify,adapter-cloudflarepackage it for those hosting services, which render pages on demand — sometimes on servers “at the edge,” physically close to your visitors.
The content is identical in all cases. What changes is when the HTML is made (ahead of time, or on each request) and where (one server, or a global network).
Why this is an SEO decision, not just a tech one
The main thing: speed. A page that’s already a static file loads almost instantly. A page that has to be built on the server takes a moment. And Google has said plainly that if your 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.” So a slow deployment doesn’t just annoy users — it can mean Google reads less of your site.
The simple version of the decision
- A content site (blog, docs, marketing) → use
adapter-staticand prerender everything. Fastest possible, nothing to break. - A content site with a few dynamic bits (search, comments) → use a server
adapter (
node/vercel/cloudflare) and mark your content pagesprerender = true, leaving the dynamic bits to render on request. - An app or dashboard with logged-in, personalized pages → render on the server (SSR), prerender only the public marketing pages.
Don’t forget the two files SvelteKit won’t make for you
SvelteKit doesn’t generate a sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing..xml or a robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. automatically. You
add them yourself — usually as a small endpoint file (sitemap.xml/+server.js)
and either a file in your static/ folder or another endpoint for
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 easy to forget because most frameworks that render HTML for
you feel “complete.” These two aren’t.
Want the deeper version — what each adapter does to renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., how
prerender = 'auto' handles a mixed site, why edge functions can’t read files,
and how the sitemap strategy changes with your adapter? Switch to the
Advanced tab.
TL;DR — The adapter doesn’t change what SvelteKit renders — it changes where and when: build-time static (
adapter-static), request-time on a server you run (adapter-node), or request-time on serverless/edge functions (adapter-vercel/-netlify/-cloudflare). Per-routeprerender = truebuilds static HTML and drops the route from the dynamic manifest;prerender = 'auto'prerendersThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal. and keeps it in the manifest — the tool for mixed/blog/[slug]sites. Edge runtimes run on V8 isolates: no Nodefs, and cold starts hurt TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good., which feeds LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. and (per Google’s crawl-budget doc) crawl capacityThe number of URLs an engine will crawl in a timeframe.. SvelteKit generates no sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing..xml or robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. — build them as+server.jsendpoints, and note the strategy depends on the adapter. This is a narrower, deployment-focused companion to the SvelteKit SEOSvelte SEO is the practice of making sure search engines and AI crawlers can see content built with Svelte. Plain Svelte is client-side rendered (a blank shell), so the key is to use SvelteKit, which renders pages on the server by default. fundamentals article in this section; I assume you already know SvelteKit is SSR-by-default and won’t re-litigate that here.
The one idea that makes all of this click
The adapter does not change what renders. It changes where and when.
That’s the whole thing. The SvelteKit docs put it precisely: adapters “take the
built app as input and generate output for deployment.” 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 Your components, your
load functions, your <svelte:head> metadata — identical across every adapter.
What differs is:
- When the HTML is produced: at build time (static/prerendered) or at request time (SSR on a server, serverless function, or edge function).
- Where it’s produced: on a single origin server, on a regional serverless function, or on an edge network close to the visitor.
Everything below is a consequence of those two axes.
Why deployment choices are SEO choices
The chain is short and well-documented: TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. → LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. → crawl capacity.
Time to first byte is how long the host takes to start sending the response. A prerendered file served from a CDN cache has a near-zero TTFB. A server that has to render the page has a higher one. A cold-starting serverless or edge function can have a much higher one on the first hit. TTFB is a direct input to Largest Contentful Paint — you can’t paint what you haven’t received — and LCP is a Core Web VitalsWeb Vitals is Google's initiative (launched May 2020) for unified page-experience quality signals. Core Web Vitals — LCP, INP, and CLS — are the subset used in ranking; the rest (TTFB, FCP, TBT, Speed Index) are diagnostic, not ranking factors. signal.
The crawl side is where Google is most explicit. From the crawl-budget documentation: “If the site responds quickly for a while, the limit goes up, meaning more connections can be used to crawl. If the site slows down or responds with server errors, the limit goes down and Google crawls less.” And the best-practice line: “Make your pages efficient to load. If Google can load and render your pages faster, we might be able to read more content from your site.” A cold-starting edge function that’s slow to respond is subject to the same dynamic as a slow origin server.
One honesty note up front: Google publishes no SvelteKit-specific guidance.
There’s no doc or Search Off the Record episode naming SvelteKit adapters,
prerender = 'auto', or edge cold starts. What I’m doing here is applying
Google’s general renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. and crawl-budget guidance to SvelteKit’s specific
mechanics — not quoting a rep who commented on SvelteKit, because none has. The
Google framing that “server-side or pre-renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. is still a great idea because
it makes your website faster for users and crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index., and not all bots can run
JavaScript” is the closest official anchor, and it’s framework-agnostic.
Choosing an adapter for SEO outcomes
adapter-auto — the zero-config default, and its ceiling
New SvelteKit projects ship with adapter-auto. It detects the platform —
Vercel, Netlify, Cloudflare Pages, Azure, AWS — and installs the matching adapter
at build time. It’s a fine starting point, but there’s a hard ceiling worth
knowing: adapter-auto does not take any options. The moment you need
{ edge: true }, Cloudflare bindings, Vercel ISR, or any platform-specific
configuration, you install the underlying adapter (adapter-vercel,
adapter-cloudflare, etc.) directly. Treat auto as a scaffold, not a production
decision.
adapter-static — full SSG, for content-first sites
adapter-static prerenders your whole site to static files at build time. No
server runs; a host serves 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 For a content-first site this is the
strongest SEO profile you can have — lowest TTFB, no cold starts, nothing to fall
over. The one requirement is the trap covered at length in the fundamentals
article: SSR must stay on during the build, or you get empty shells instead of
rendered HTML. I won’t re-explain that here beyond flagging it.
The catch is rigidity. Anything that genuinely needs server logic per request (true search, per-user content, form handling without a third-party endpoint) can’t live on a purely static build — which is exactly what the next adapters are for.
adapter-node — a server you control
adapter-node produces a standalone Node.js server. You run it, you scale it, you
own the TTFB. This is the most flexible option and the one with the fewest runtime
surprises — full Node APIs, including fs. It’s a good fit when you have
infrastructure already, need Node libraries that edge runtimes can’t run, or want
predictable (non-cold-starting) response times from a warm server. The tradeoff is
operational: you’re running a server, and its speed and uptime are now your crawl
capacity.
adapter-vercel — serverless, edge, and ISR
adapter-vercel deploys to Vercel’s serverless functions by default, with several
SEO-relevant levers set per route via export const config:
runtime: 'edge'moves that route to Vercel’s edge runtime (more below).regionscontrols where serverless functions run — closer to your users (or your database) means lower latency.isrenables Incremental Static Regeneration:isr: { expiration: 60 }serves a cached static asset and regenerates it after the window, giving “the performance and cost advantages of prerendered content with the flexibility of dynamically rendered content.” ISR is a genuine fourth path between pure-static and pure-SSR — but note the docs’ own caveat: “Using ISR on a route withexport const prerender = truewill have no effect, since the route is prerendered at build time.” ISR and prerender are alternatives, not stackable.
adapter-cloudflare — Workers/Pages, global edge
adapter-cloudflare targets Cloudflare WorkersA serverless function that runs at Cloudflare's global edge, close to every user. and Pages — SSR on a global edge
network, often the lowest TTFB for a geographically spread audience. The important
constraint is the runtime: Workers run on V8 isolates, not Node. From the docs:
“You can’t use fs in Cloudflare Workers.” Some Node APIs work only behind the
nodejs_compat compatibility flag, and even then support isn’t one-to-one. If you
were reading files at request time (a redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. map, a data file, custom OG-image
inputs), that code needs a rethink — covered in the edge section below.
(The older adapter-cloudflare-workers is deprecated; new projects use
adapter-cloudflare, which handles both Workers and Pages. If you’re on the old
one, migrating is the recommended path.)
adapter-netlify — functions or Edge Functions (Deno)
adapter-netlify deploys to Netlify’s Node-based functions by default, or to
Deno-based Edge Functions with edge: true. Same shape as Vercel: default
serverless with an edge opt-in. One SvelteKit-specific footnote — Netlify Forms
require the form’s page to be prerendered so Netlify can detect the form markup
at deploy time, which is a small “prerender this route” requirement layered on top
of the adapter choice.
The decision, in one line each
- 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 only the static shell (marketing, login).
- Global, TTFB-critical audience → an edge adapter for the dynamic routes, accepting the Node-API constraints and cold-start reality.
(The Decision Tree tab walks this as a branching flow.)
Prerendering strategy for mixed sites
What true / false / 'auto' actually do
export const prerender is a per-route (or per-layout) page option, and the three
values aren’t just on/off:
true— build this route to static HTML at build time. Critically, it’s “excluded from manifests used for dynamic SSR, making your server (or serverless/edge functions) smaller.” Once prerendered, the route can’t fall back to dynamic rendering — it’s static, full stop.false— always render on request. No static file.'auto'— the mixed-site tool. It prerenders the route and keeps it in the dynamic server manifest, so the same route can be served statically for known paths and server-rendered for the rest. This is built for exactly the case the docs describe: a route like/blog/[slug]“where you want to prerender your most recent/popular content but server-render the long tail.”
Because prerendered routes shrink the server bundle, a mostly-prerendered site
with a few 'auto'/false routes deploys a smaller, cheaper, faster function —
an efficiency win independent of SEO.
Dynamic routes need an entries function
The prerender crawler discovers pages by following <a> links from your entry
points. That works for static routes, but a dynamic route like /blog/[slug] has
no fixed URL for the crawler to find. If nothing links to a given slug, SvelteKit
won’t know it exists — and you’ll hit the classic build error that routes “were
marked as prerenderable, but were not prerendered.”
The fix is an explicit entries function (or config.kit.prerender.entries) that
enumerates the parameter values:
// src/routes/blog/[slug]/+page.server.js
export const prerender = true;
export function entries() {
return [
{ slug: 'hello-world' },
{ slug: 'sveltekit-deployment-seo' },
];
}In practice you generate that list from your CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. or content directory. Without it, prerendering only covers the slugs the link crawler happens to find.
The /blog/[slug] pattern in the wild
Put the two together and you have the canonical mixed-site setup: prerender = 'auto' plus an entries function that returns your recent and popular posts.
Those get static HTML at build time; anything not in the list falls through to SSR
on demand. New posts render dynamically until the next build prerenders them. It’s
the pragmatic middle ground between “prerender all 40,000 posts every build” and
“render every post on every request.”
Edge runtime constraints that affect 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' };That means you can push high-traffic, cacheable routes to the edge for low TTFB while keeping Node-dependent routes on the standard serverless (Node) runtime in the same deployment. Mix deliberately.
No fs, no 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: “You can’t use fs in
Cloudflare Workers.” Vercel’s: “You can’t use fs in edge functions.” Both point
to the same two escape hatches: use the read helper from $app/server to access
bundled assets, or “prerender the routes in question” so the file access happens
at build time instead of at request time.
The SEO-adjacent cases where this bites: dynamic OG-image generation that reads a
font or template file, file-based redirect maps, or a sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. endpoint that reads
content off disk. Any of those either moves to $app/server’s read() or moves to
prerender/build time. It’s not a blocker — it’s a “know before you pick edge”
constraint.
Cold starts and TTFB — when edge helps and when it doesn’t
Edge functions still cold-start. A cold edge function on its first request can be slower than a warm Node server, and dramatically slower than a prerendered file served from cache. Edge wins when the function stays warm or when it’s paired with aggressive caching so most requests never hit the function at all. It is not automatically the fastest option — “deploy to the edge” is not a synonym for “faster.” For a content site, prerendered static output beats edge SSR on TTFB every time, because there’s no function to start.
Generating sitemap.xml and robots.txt (SvelteKit won’t)
This is the gap most SvelteKit tutorials skip and most audits catch. SvelteKit generates no sitemap.xml and no robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. automatically — regardless of adapter, regardless of how many pages you prerender. A fully static site with thousands of prerendered pages still ships with no sitemap unless you build one.
The +server.js endpoint pattern
The idiomatic sitemap is a route endpoint that returns XML with the right
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 depends on your adapter
Here’s the part that ties this whole article together: your sitemap strategy is downstream of your adapter choice.
- On
adapter-static, the sitemap endpoint needsexport const prerender = trueso it’s included in the static output — there’s no server at runtime to generate it on request. It’s baked at build time, which means it’s only as fresh as your last build. - On a Node/serverless/edge adapter, the same endpoint can generate the sitemap
dynamically per request from your CMS or database — always current, no rebuild
needed. (On an edge adapter, remember the
fsconstraint: pull URLs from an API or binding, not a disk read.)
So the “should my sitemap be static or dynamic?” question isn’t a separate decision — it falls out of the adapter you already chose.
robots.txt: static file vs. endpoint
Two options. Drop a plain robots.txt in your static/ folder (served at
/robots.txt automatically), which is the simplest choice and fine for most sites.
Or generate it from a src/routes/robots.txt/+server.js endpoint when you need it
to differ by environment (blocking crawlers on staging, allowing them in
production, for instance). Either way, don’t block your /_app/ bundle or CSS —
that breaks rendering for engines that do render.
If you’re coming at this from the broader framework or JavaScript-SEO angle, the “where and when does rendering happen” logic here is the same logic that governs JavaScript SEOMaking sure search engines can crawl, render, and index content that depends on JavaScript. generally, and the SvelteKit fundamentals piece in this section covers the rendering modes and metadata patterns this article builds on top of.
AI summary
A condensed take on the Advanced version:
- The adapter changes where and when, not what. Adapters “take the built app as input and generate output for deployment” — same content, different timing (build vs. request time) and location (origin vs. edge).
- Why it’s an SEO decision: TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. → LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. → crawl capacityThe number of URLs an engine will crawl in a timeframe.. Google: if a site “responds quickly… the limit goes up… If the site slows down… Google crawls less.” No Google guidance names SvelteKit specifically — this is general guidance applied to SvelteKit mechanics.
- Adapters:
adapter-auto(zero-config, no options);adapter-static(SSG, content sites, lowest TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good.);adapter-node(server you control, full Node APIs);adapter-vercel(serverless + edge + ISR);adapter-cloudflare(global edge Workers, nofs;adapter-cloudflare-workersis deprecated);adapter-netlify(functions or Deno Edge Functions). - PrerenderThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal.:
truebuilds static HTML and removes the route from the dynamic manifest;falsealways SSRs;'auto'prerenders and keeps it dynamic — the mixed-site tool for/blog/[slug](prerender popular, SSR the long tail). - Dynamic routes need an
entriesfunction or you hit the “marked as prerenderable, but were not prerendered” error. - Edge constraints:
runtime: 'edge'is per-route (Vercel); nofs(“You can’t use fs in Cloudflare WorkersA serverless function that runs at Cloudflare's global edge, close to every user.” / edge functions) — use$app/server’sread()or prerender; cold starts can make edge slower than a warm server or static file. - No built-in sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing./robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere.. Build a
sitemap.xml/+server.jsendpoint (prerender = trueonadapter-static; dynamic on server/edge adapters). robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. viastatic/or an endpoint. - ISR ≠ prerender-plus: “Using ISR on a route with
export const prerender = truewill have no effect.” They’re alternatives.
Official documentation
Primary-source documentation from SvelteKit and the search engines.
SvelteKit
- Adapters • SvelteKit Docs — the overview: adapters take the built 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 path.
- Netlify (adapter-netlify) • SvelteKit Docs — Node Functions vs. Deno-based Edge Functions (
edge: true), and the Forms prerenderThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal. requirement. - Page options (prerender, ssr, csr, config) • SvelteKit Docs —
prerender = true/false/'auto', theentriesfunction, and per-routeconfigincludingruntime: 'edge'.
- Understand JavaScript SEO Basics — the render queue and “not all botsA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. can run JavaScript.”
- Optimize your crawl budget — crawl capacityThe number of URLs an engine will crawl in a timeframe. tied to response speed; “make your pages efficient to load.”
Bing / Microsoft
- bingbot Series: JavaScript, Dynamic Rendering, and Cloaking. Oh My! — Bing’s prerenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM./dynamic-renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. recommendation and the cloaking clarification.
- Fast Front-End Performance for Microsoft Bing — Bing’s own 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. Each link is a deep link that 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 default 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]case where you want to “prerenderThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal. 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 WorkersA serverless function that runs at Cloudflare's global edge, close to every user..” 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 — renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. & crawl budgetThe number of URLs an engine will crawl in a timeframe.
- “Keep in mind that server-side or pre-renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. is still a great idea because it makes your website faster for users and crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index., 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 own edge architecture
- “We encourage detecting our bingbotBingbot is Microsoft Bing's primary web crawler — the bot that discovers, fetches, and renders pages to build the Bing index. That index also powers Yahoo, DuckDuckGo, Ecosia, and Microsoft Copilot, so Bingbot's reach is far wider than Bing's own search-market share. user agentA user agent is the HTTP request header a client (browser, crawler, or bot) sends to identify itself. For crawlers, a short user-agent token — a substring of that string — is what robots.txt rules actually target., 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 own SSR + edge architecture. Jump to quote
SvelteKit deployment SEO checklist
A pass to confirm your adapter, prerenderThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal., and sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. setup won’t hurt crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.:
- You’ve moved off
adapter-autoto an explicit adapter if you need any configuration (edge, ISR, bindings). - The adapter matches the site type —
adapter-staticfor pure content, a server/edge adapter for anything with per-request logic. - Content routes are
prerender = true(or'auto'); only genuinely dynamic routes are left to SSR. - Mixed dynamic routes (
/blog/[slug]) useprerender = 'auto'with anentriesfunction enumerating known paths. - No unresolved “marked as prerenderable, but were not prerendered” build errors.
- If any route uses
runtime: 'edge', it does not call Nodefs— file access uses$app/server’sread()or is prerendered. - You’ve accounted for cold starts on edge/serverless — cacheable, static, or warm where TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. matters.
- A sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing..xml endpoint exists (
prerender = trueonadapter-static; dynamic on server/edge adapters). - A robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. exists (in
static/or as a+server.jsendpoint) and does not block/_app/or CSS. - You are not trying to stack ISR on a
prerender = trueroute (it has no effect). - You verified the rendered HTML and response speed in GSCA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. and PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking..
The mental models
1. Where and when, not what. The adapter never changes your content — it changes when the HTML is made (build time vs. request time) and where (origin vs. edge). Every deployment SEO question reduces to those two axes. Ask them before you touch config.
2. PrerenderThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal. removes a route from the server.
prerender = true isn’t just “make it static” — it takes the route out of the
dynamic manifest. That shrinks your function and rules out a dynamic fallback.
'auto' is the exception: prerendered and still in the manifest.
3. The /blog/[slug] split.
The default pattern for real content sites: prerender the entries you can name
(entries function returns recent/popular), SSR the long tail. 'auto' is the
switch that makes both true at once.
4. Edge is a trade, not an upgrade.
Edge buys you geographic proximity (low TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. when warm) and costs you Node APIs
(no fs) and cold-start risk. It beats a warm Node server only sometimes, and
loses to prerendered static output on TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. always. Choose it for a reason, not by
default.
5. The sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. follows the adapter.
“Static or dynamic sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing.?” isn’t a separate decision. adapter-static →
prerendered sitemap, fresh only at build. Server/edge adapter → per-request
sitemap, always current. The adapter already answered the question.
6. Nothing generates the two files. SvelteKit makes no sitemap.xml and no robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere., for any adapter. If you didn’t write them, they don’t exist. Bake this into your launch checklist.
Which adapter + prerender combo should I pick?
The core “which path do I take?” question in SvelteKit deployment is how should this site ship? Walk your site through this:
1. Does any page need per-request server logic — auth, personalization, live search, form handling, per-user data? → No (every page is the same for every visitor): go to 2. → Yes: skip to 3.
2. Pure content site (blog, docs, marketing).
→ Use adapter-static, set prerender = true site-wide (or in the root
layout). Add a prerendered sitemap.xml/+server.js (prerender = true) and a
static/robots.txt. Lowest TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good., no cold starts, nothing to run. Stop here.
3. Is the whole site dynamic, or just some routes? → Just some routes (mostly content, a few dynamic bits): go to 4. → Mostly/entirely dynamic (app, dashboard, ecommerce with per-user data): go to 5.
4. Content site with dynamic pockets.
→ Use a server/edge adapter (adapter-node, -vercel, or
-cloudflare). Mark content routes prerender = true, dynamic routes
false. For /blog/[slug]-style routes with known-popular content, use
prerender = 'auto' + an entries function. Generate the sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. dynamically
from your CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms.. Done.
5. App / dashboard / ecommerce (SSR-first). Now pick where SSR runs:
→ Predictable latency, Node libraries, you have infra: adapter-node
(warm server, full Node APIs, no cold-start surprises).
→ Global audience, TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. matters most, no heavy Node deps: an edge adapter
(adapter-cloudflare, or adapter-vercel with runtime: 'edge' per route) —
accept no fs (use $app/server’s read() or prerenderThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal.) and cold starts.
Prerender only the truly static shell (marketing, login).
Fourth path (Vercel only): if a route is “mostly static but occasionally
changes,” consider ISR (isr: { expiration }) instead of prerender = true
— never both, since “ISR on a route with export const prerender = true will have
no effect.”
Should my sitemap be static or dynamic?
On adapter-static? → Static/prerendered sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. endpoint
(prerender = true). It’s baked at build; fine for sites that rebuild on publish.
On a Node/serverless/edge adapter? → Dynamic sitemap generated per request
from your CMS/DB — always current, no rebuild. (On edge, pull URLs from an API or
binding, not a disk fs read.)
Never: ship no sitemap because “the pages are all static.” Static output and sitemap discoverability are unrelated — SvelteKit generates neither file for any adapter.
SvelteKit deployment SEO — cheat sheet
Adapters at a glance
| Adapter | Renders | Runtime | SEO note |
|---|---|---|---|
adapter-static | Build time (SSG) | none | Lowest TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good., no cold starts; content sites |
adapter-node | Request time (SSR) | Node | Full Node APIs (fs ✅); you run the server |
adapter-vercel | Request time | serverless / edge | Per-route runtime, regions, ISR |
adapter-cloudflare | Request time | V8 edge | Global edge; no fs; nodejs_compat |
adapter-netlify | Request time | Node / Deno edge | edge: true for Deno Edge Functions |
adapter-auto | (detects above) | — | Takes no options — scaffold only |
PrerenderThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal. values
| Value | Static HTML? | In dynamic manifest? | Use for |
|---|---|---|---|
true | ✅ | ❌ (removed) | Known static content routes |
false | ❌ | ✅ | Genuinely dynamic routes |
'auto' | ✅ | ✅ | /blog/[slug] — prerender popular, SSR long tail |
Fast rules
- Dynamic prerendered routes → add an
entriesfunction (or hit the “not prerendered” error). runtime: 'edge'is per-route (Vercel) — mix edge and Node routes.- Edge = no
fs→ use$app/server’sread()or prerender. - Cold starts make edge slower than a warm server / static file on first hit.
- ISR ≠ prerender —
isron aprerender = trueroute does nothing. - No auto sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing./robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. — build both.
prerender = trueon the sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. endpoint foradapter-static; dynamic on server/edge. - Never block
/_app/or CSS in robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere..
A prerendered route is missing from the deployment
Likely cause: the crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. could not discover the path, an entries value is absent, or prerenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. failed. Fix: add crawlable links or explicit entries and treat build warnings as release failures. Confirm: the output manifest contains the route and production returns complete HTML.
adapter-static fails on a dynamic route
Likely cause: the route cannot be fully enumerated at build time. Fix: supply finite entries, redesign the route, or use a server-capable adapter for that path. Confirm: the selected adapter builds and every representative route returns the intended response.
Edge deployment throws filesystem or Node API errors
Likely cause: route code or a dependency assumes Node features unavailable in the edge runtime. Fix: replace the dependency, move the work to a compatible service, or choose a Node adapter. Confirm: production SSR succeeds without runtime exceptions.
Sitemap or robots.txt returns HTML
Likely cause: a fallback route catches the endpoint or the +server handler sets the wrong body/headers. Fix: create explicit endpoint handlers with correct content types. Confirm: direct requests return the expected text/XML response and 200 status.
Metadata differs between prerendered and SSR routes
Likely cause: head data is loaded in different code paths or depends on browser state. Fix: centralize metadata generation from server/build-safe page data. Confirm: raw HTML for both route types contains equivalent title, canonical, and robots logic.
Confirm what your adapter actually shipped
The point of picking an adapter and prerenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. is that a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. gets fast, complete HTML. These checks confirm that’s what actually happened — from the raw response, not the browser.
Is the page prerendered/SSR’d (content in raw HTML)?
A plain curl runs no JavaScript, so it sees exactly what a non-renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.
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)?
TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. feeds LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. and crawl capacityThe number of URLs an engine will crawl in a timeframe., so measure it. Hit the URL cold, then 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 should be consistently low. A large first value that drops on the second hit is a classic serverless/edge cold start.
Was this 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) means you’re being served cached/prerendered content;
a MISS/DYNAMIC on every request means it’s rendering per request.
Does the sitemap actually exist and return XML?
Since SvelteKit doesn’t generate one, verify yours is really there with the right 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 the browser console to compare rendered DOM against what a crawler needs —
if your headline is here but missing from the curl output above, 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')));Check 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 your CSS means
engines can’t render the page — almost always a mistake.
Patrick's relevant free tools
- Google Index Checker — Check one URL’s observable indexability blockers, or reconcile sitemap, crawl, and supplied Search Console evidence across a URL set before verifying Google’s actual state in URL Inspection.
- Canonicalization Checker — Audit HTML and HTTP canonical signals, test the canonical target, and identify observable conflicts that can cause Google to choose a different URL.
- SEO Incident Simulator — Practice thirty deterministic technical SEO incident investigations — indexability, crawl controls, redirects, sitemaps, markup, caching, DNS, bot verification, rendering, hreflang, and faceted navigation — with clearly labeled fixture evidence and Find → Fix → Verify handoffs.
Tools for debugging SvelteKit deployment SEO
- URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. (Google Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results.) — the source of truth. Live-test a URL and check the rendered HTML, screenshot, and page resources to confirm content and metadata are present and nothing is blocked.
- PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. — the SvelteKit docs’ own recommended tool; surfaces TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. and the Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. (LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good./INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good./CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.) that your adapter choice most affects.
- WebPageTestWebPageTest is a free, open-source, lab-based website performance testing tool — created by Patrick Meenan in 2008 and acquired by Catchpoint in 2020 — that runs pages on real browsers from distributed locations and produces deep diagnostics (waterfalls, filmstrips, connection views, Core Web Vitals). It's a diagnostic tool, not a Google ranking input. — waterfall + filmstrip for diagnosing TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. and cold-start timing on edge/serverless deploys.
curl -w "%{time_starttransfer}"— the quickest raw TTFB and cold-start check (see the Scripts tab).- Host dashboards (Vercel / Cloudflare / Netlify Analytics) — function invocation counts, cold-start rates, and cache-hit ratios per route — the ground truth for whether edge/serverless is actually fast for you.
- Screaming Frog SEO Spider — crawl with JS renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. on/off to diff raw vs. rendered HTML across the site and confirm prerendered routes are complete.
- Ahrefs Site Audit — surfaces missing/blocked sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., redirect chainsA → B → C instead of A → C. Each hop loses link equity and adds latency., broken canonicals, and indexability issues at scale.
Test yourself: SvelteKit Deployment SEO
Five quick questions on adapters, prerenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., and edge renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. in SvelteKit. Pick an answer for each, then check.
Resources worth your time
My related writing
- JavaScript SEO: A Definitive Guide — my full reference on renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. modes (SSR, static renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., prerendering, and the CSR pitfalls) that underpin every adapter decision here. As I put it there, any kind of SSR, static rendering, or prerendering setup is going to be fine for search engines — which is exactly the safety net behind these adapter choices.
- The Beginner’s Guide to Technical SEO — where rendering, crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor., and Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. fit in the bigger picture.
My speaking
- How Search Works (SlideShare) — my walkthrough of crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor., rendering, indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., and ranking, which is the backdrop for why TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. and rendering timing matter. (My standing disclaimer applies: “This is my understanding of systems… not going to be 100% complete or accurate.”)
From around 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
prerendervalues, theentriesfunction, and per-routeconfigincludingruntime: 'edge', in the team’s own words. - Vercel (adapter-vercel) • SvelteKit Docs — the edge runtime, regions, and the ISR-vs-prerenderThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal. 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: Your Secret Weapon (Okupter) — a practitioner guide to prerendering, meta tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored., and the
+server.jssitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing./RSS pattern. - A Deep Dive into SvelteKit’s Rendering Techniques (This Dot Labs) — SSR/SSG/CSR mechanics and per-route/per-layout config, with the “SSR can be expensive” server-load tradeoff.
- Understand JavaScript SEO Basics (Google Search Central) — the render queue and “not all bots can run JavaScript,” the general guidance every adapter choice sits under.
SvelteKit Deployment SEO
SvelteKit deployment SEO is the set of build- and deploy-time decisions — which adapter converts the build for a hosting target, which routes are prerendered vs. server-rendered vs. edge-rendered, and how sitemap.xml and robots.txt are generated — that decide whether a crawler gets fast, complete HTML.
Related: Svelte SEO, JavaScript SEO
SvelteKit Deployment SEO
SvelteKit deployment SEO covers the decisions made at build and deploy time that determine where and when a SvelteKit page renders — and therefore how fast, and how complete, the HTML a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. receives is. It assumes you already know SvelteKit renders server-side by default; the question here is how it ships.
The adapter is the plugin that “take[s] the built app as input and generate[s] output for deployment.” It doesn’t change what SvelteKit renders, only where and when: adapter-static builds every page to static HTML at build time; adapter-node runs SSR on a server you control; adapter-vercel, adapter-netlify, and adapter-cloudflare run SSR at request time on serverless or edge infrastructure. adapter-auto detects the platform and installs the matching one, but takes no configuration options.
The per-route prerender option (true, false, or 'auto') decides whether a page is built as static HTML or rendered per request. 'auto' is the mixed-site tool — it prerendersThe Speculation Rules API is a Chromium browser API (Chrome/Edge 109+) that lets a site tell the browser which same-site pages to prefetch (download the HTML document) or prerender (fully load and render in an invisible tab) before a visitor clicks — so the next navigation can be near-instant. It's a browser-side performance feature for real users, not a crawling, indexing, or ranking signal. a route and keeps it in the dynamic manifest, so a route like /blog/[slug] can serve popular posts statically and the long tail dynamically.
Two SvelteKit-specific gaps make this an SEO topic and not just a DevOps one: edge runtimes (Cloudflare WorkersA serverless function that runs at Cloudflare's global edge, close to every user., Vercel Edge Functions) run on V8 isolates without Node’s fs, and they cold-start — which affects TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good., and TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. feeds LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. and crawl capacityThe number of URLs an engine will crawl in a timeframe.; and SvelteKit generates no sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing..xml or robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. automatically, so those are +server.js endpoints you build yourself, with the strategy itself depending on the adapter you chose.
Related: Svelte SEO, JavaScript SEO
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.