· 8 min read
Server-Side Rendering vs Static Generation in SvelteKit
SvelteKit lets you mix SSR, SSG, and client-side rendering on a per-route basis. Here's when to use each approach and how to combine them effectively.
By Tanner Goins

One of SvelteKit’s best features is one that most tutorials gloss over: you don’t have to pick one rendering strategy for your entire site. You can render your marketing pages statically, your dashboard with server-side rendering, and your interactive widgets client-side. All in the same project, with the same components.
After building and rebuilding this site and living with these patterns for over a year in Svelte 5, I’ve developed strong opinions about when each approach makes sense. Here’s the practical guide.
The Three Rendering Strategies
Before diving into when to use what, let’s be precise about what each strategy does.
Static Generation (SSG / Prerendering)
The page is built once at deploy time. The HTML file is generated, saved, and served directly from a CDN. No server runs at request time.
In SvelteKit, you enable this per route:
// +page.ts
export const prerender = true; Result: A static HTML file. Lightning fast. No server needed.
Server-Side Rendering (SSR)
The page is rendered on the server for every request. The server runs your load function, generates HTML, and sends it to the client.
This is SvelteKit’s default behavior. If you don’t set prerender = true, your page is server-rendered.
// +page.server.ts
export async function load({ params }) {
const post = await db.getPost(params.slug);
return { post };
} Result: Fresh data on every request. Requires a running server.
Client-Side Rendering (CSR)
The page is rendered entirely in the browser. The server sends a minimal HTML shell, and JavaScript takes over to fetch data and render the UI.
// +page.ts
export const ssr = false; Result: No server rendering at all. Data fetched client-side. Not SEO-friendly.
When to Use Static Generation
Use SSG when the content doesn’t change between deployments.
Static generation is the fastest and cheapest option. The HTML is pre-built, cached on a CDN edge node, and served in milliseconds. There’s no server to maintain, no cold starts, no database queries at request time.
Perfect For
Blog posts and documentation. This site’s blog posts are prerendered. The content is in markdown files that change only when I deploy. There’s no reason to render them on every request when the result would be identical every time.
// src/routes/blog/[post]/+page.ts
export const prerender = true; Marketing pages. Homepage, about page, pricing page, services page. These change infrequently and benefit enormously from edge caching. For a small business website, prerendering the entire site is often the right call.
Sitemaps and RSS feeds. Generated once at build time from your content:
// src/routes/sitemap.xml/+server.ts
export const prerender = true; Legal pages. Privacy policy, terms of service. Static content that rarely changes.
The Tradeoffs
- Content is only as fresh as your last deploy. If you update a blog post, the change won’t be visible until you redeploy.
- Dynamic routes need to be enumerable. SvelteKit needs to know every URL to prerender at build time. For blog posts, this means you need an
entries()function that returns all slugs. - No per-request personalization. Every visitor sees the same page. If you need “Welcome back, Sarah” in the header, SSG alone can’t do it.
When to Use Server-Side Rendering
Use SSR when the content depends on the request: the user, the time, the query parameters, or data that changes between requests.
Perfect For
Dashboards and authenticated pages. The content varies per user. You need to check their session, query their data, and render a personalized page. SSR handles this naturally:
// src/routes/dashboard/+page.server.ts
export async function load({ locals }) {
const user = locals.user;
const orders = await db.getOrders(user.id);
return { user, orders };
} Search results. The content depends on the query. You can’t prerender every possible search. You need to run the query at request time.
Real-time data. Stock prices, weather, live scores. The data changes constantly, so a prerendered page would be immediately stale.
Pages with access control. If some pages should only be visible to authenticated users, SSR lets you check authentication server-side and redirect if needed:
// src/routes/admin/+page.server.ts
export async function load({ locals }) {
if (!locals.user?.isAdmin) {
throw redirect(303, "/login");
}
return { users: await db.getAllUsers() };
} The Tradeoffs
- Requires a running server. You can’t deploy to a static host. You need a Node.js server, a serverless function, or an edge runtime.
- Slower than static. Every request runs server-side code. Even with caching, this is slower than serving a pre-built HTML file.
- Cold starts. On serverless platforms, the first request after an idle period can be slow. Subsequent requests are faster, but the initial latency is noticeable.
SSR + Caching: The Best of Both Worlds
For pages that change occasionally but not on every request, combine SSR with HTTP caching:
// +page.server.ts
export async function load({ setHeaders }) {
setHeaders({
"cache-control": "public, max-age=300", // Cache for 5 minutes
});
const products = await db.getProducts();
return { products };
} This gives you fresh data (within 5 minutes) with the performance of serving cached responses. It’s my go-to pattern for product listings, category pages, and anything that changes daily rather than per-request.
When to Use Client-Side Rendering
Use CSR sparingly, for highly interactive components that don’t need SEO and rely on client-side state.
Perfect For
Interactive tools and calculators. A mortgage calculator, a color picker, a configuration builder. These are user-driven interactions that don’t need to be indexed by search engines.
Authenticated app shells. If your entire application is behind a login, search engines can’t access it anyway. CSR can work for the app interior while SSR handles the login page.
The Tradeoffs
- Not SEO-friendly. Search engines may not execute JavaScript reliably. If the page needs to rank in search results, don’t use CSR.
- Slower initial load. The browser downloads JavaScript, executes it, fetches data, then renders. Users see a loading spinner instead of content.
- Accessibility concerns. Screen readers and assistive technologies work better with server-rendered HTML than with JavaScript-generated DOM.
My recommendation: avoid CSR as a page-level strategy. Use it for individual components within an SSR or SSG page when those components need client-side interactivity.
Mixing Strategies in SvelteKit
This is where SvelteKit shines. You configure rendering per route, not per project.
This Site’s Strategy
Here’s roughly how this site is set up:
| Route | Strategy | Why |
|---|---|---|
/ (homepage) | SSR | Dynamic content sections |
/blog | SSR | Blog listing with categories |
/blog/[post] | Prerendered | Content is static markdown |
/about | Prerendered | Rarely changes |
/contact | SSR | Form handling server-side |
/resume | Prerendered | Rarely changes |
/sitemap.xml | Prerendered | Generated at build time |
Layout-Level Configuration
SvelteKit lets you set rendering defaults at the layout level, so all child routes inherit the setting:
// src/routes/blog/+layout.ts
export const prerender = true; Now every route under /blog/ is prerendered by default. If a specific route needs SSR, it can override:
// src/routes/blog/search/+page.ts
export const prerender = false; // Override: this page needs SSR The entries() Function
For prerendered dynamic routes, SvelteKit needs to know which URLs exist at build time:
// src/routes/blog/[post]/+page.ts
export const prerender = true;
export function entries() {
return [
{ post: "my-first-post" },
{ post: "another-post" },
// ... all post slugs
];
} In practice, you’d generate this list from your content source (reading markdown files, querying a CMS, etc.).
How Rendering Strategy Affects SEO
The rendering strategy you choose has direct implications for how search engines see your pages. This matters for your SEO strategy.
Prerendered Pages
Search engines love these. The HTML is complete, fast to load, and easy to crawl. This is the best option for any page that needs to rank.
Server-Rendered Pages
Also excellent for SEO. The HTML is complete when the crawler receives it. The main risk is if your server is slow. Slow pages get lower crawl priority and worse Core Web Vitals scores.
Client-Rendered Pages
Risky for SEO. Google claims to render JavaScript, but the rendering budget is limited. Important pages should never rely on client-side rendering for their primary content.
The Practical Rule
If the page needs to appear in search results, prerender it or server-render it. If it doesn’t need SEO (authenticated dashboards, internal tools), CSR is fine.
Performance Comparison
Here’s how the strategies compare on the metrics that matter:
| Metric | SSG | SSR | CSR |
|---|---|---|---|
| Time to First Byte (TTFB) | Excellent (CDN edge) | Good (server response) | Fast (empty shell) |
| First Contentful Paint (FCP) | Excellent | Good | Poor (waits for JS) |
| Largest Contentful Paint (LCP) | Excellent | Good | Poor |
| Cumulative Layout Shift (CLS) | Excellent (stable) | Good | Risky (content shifts) |
| Hosting cost | Lowest (static files) | Medium (server) | Lowest (static files) |
| Data freshness | Deploy-time only | Real-time | Real-time |
For most small business and content sites, prerendering wins across the board. The hosting cost alone (static files on a CDN vs. a running server) can be the deciding factor. This is one of the reasons I advocate for choosing technology that fits the need, not the trend.
Start Simple
If you’re building a new SvelteKit project and aren’t sure which strategy to use, start here:
- Prerender everything you can. Blog posts, marketing pages, docs: if it doesn’t change per request, prerender it.
- Use SSR for authenticated or dynamic pages. Dashboards, search, user-specific content.
- Avoid CSR for full pages. Use it for individual interactive components, not as a page-level strategy.
- Add caching to SSR pages that don’t need real-time freshness.
SvelteKit makes this easy because you can change the strategy for any route by adding a single line of configuration. Start with the simplest approach and adjust as your needs become clearer.
The rendering strategy isn’t something to agonize over. Pick the right default, override where needed, and move on to building features.