Skip to main content
Svelte components can be rendered on the server, sent as HTML to the browser, and then made interactive through a process called hydration. This approach improves initial page load performance and SEO.

Rendering Modes

Client-Side Rendering (CSR)

The browser downloads JavaScript, executes it, and renders the page:
Pros:
  • Full interactivity immediately
  • Simpler deployment (static hosting)
  • No server required
Cons:
  • Slower initial load
  • Poor SEO (content not in initial HTML)
  • Blank page until JavaScript executes

Server-Side Rendering (SSR)

The server generates HTML and sends it to the browser:
Pros:
  • Fast initial page load
  • Better SEO (crawlers see content)
  • Works without JavaScript
Cons:
  • No interactivity until JavaScript loads
  • Requires server infrastructure
  • More complex deployment

Hydration (SSR + CSR)

Combine SSR and CSR for the best of both worlds:
Svelte components are always hydratable in Svelte 5. The hydratable compiler option from Svelte 4 has been removed.

Using the Render API

Basic Server Rendering

The render function from svelte/server generates HTML:

Handling <svelte:head>

Content in <svelte:head> is returned separately:
App.svelte

Async Server Rendering

Svelte 5 supports asynchronous server rendering with await expressions:
When using await in components, you must await the render() call. The promise will resolve once all async operations complete.

Hydration Process

How Hydration Works

During hydration, Svelte:
  1. Walks the server-rendered DOM
  2. Attaches event listeners
  3. Initializes reactive state
  4. Makes the application interactive
Props passed to hydrate() should match the props used during render() to avoid hydration mismatches.

Hydration Markers

Svelte 5 uses HTML comments as markers for efficient hydration:
Don’t remove comments from server-rendered HTML! They’re essential for proper hydration.

Hydration Mismatches

A hydration mismatch occurs when server and client HTML differ:
This causes a hydration_mismatch warning because the time will be different when rendered on the server vs. when hydrating on the client. Solutions:
  1. Use client-only rendering for dynamic values:
  1. Use hydratable for values that should be consistent:

Optimizing Data Fetching

The hydratable API

Avoid fetching data twice (server + client) with hydratable:

Serialization

hydratable uses devalue which supports:
  • Primitives (string, number, boolean, null, undefined)
  • Objects and arrays
  • Date, Map, Set, RegExp
  • BigInt, URL
  • Promises (Svelte-specific enhancement)
Functions, symbols, and DOM nodes cannot be serialized. Keep hydratable data JSON-like when possible.

Content Security Policy (CSP)

hydratable injects a script tag. For CSP compliance, provide a nonce:
For static sites, use hash-based CSP:
Prefer nonce over hash for dynamic SSR. Hash-based CSP will interfere with streaming SSR in future Svelte versions.

SSR Considerations

Browser-Only Code

Some code should only run in the browser:
$effect callbacks never run on the server, so you don’t need if (browser) checks inside them.

Lifecycle Hooks

Only onDestroy runs during SSR:

Invalid HTML Structure

Browsers “repair” invalid HTML, causing hydration mismatches:
Svelte warns about invalid structures with node_invalid_placement_ssr.

Using SvelteKit

For production applications, use SvelteKit which handles:
  • Automatic SSR/hydration setup
  • Data loading with load functions
  • Routing and navigation
  • Deployment adapters
  • Streaming SSR
  • Prerendering
+page.svelte
+page.server.js
SvelteKit is the recommended way to build Svelte apps with SSR. It handles the complexity of server/client coordination for you.

Best Practices