Open-Source Wikis

/

Svelte

/

Packages

/

Server runtime

sveltejs/svelte

Server runtime

Active contributors: Rich Harris, Simon H, Dominic Gannaway

Purpose

The server runtime turns a compiled component into an HTML string (plus collected <head> content and a CSP nonce list). It's intentionally smaller than the client runtime — there's no scheduler, no DOM diffing, just a tree of Renderer nodes that emit strings.

The public entry is packages/svelte/src/server/index.js, which simply re-exports render from packages/svelte/src/internal/server/index.js. User code imports it as import { render } from 'svelte/server'.

Directory layout

src/internal/server/
├── index.js          # public render(component, options) entry
├── renderer.js       # Renderer class — string-tree builder
├── render-context.js # per-request context (head, css, csp)
├── context.js        # ssr_context push/pop, getContext on the server
├── blocks/           # async block helpers (await/snippet)
├── hydration.js      # comment markers (HYDRATION_START / HYDRATION_END)
├── hydratable.js     # the server-side `hydratable()` wrapper
├── errors.js, warnings.js   # generated from messages/server-*
├── crypto.js         # tiny non-cryptographic id helper
├── abort-signal.js   # AbortSignal stub for non-DOM env
├── dev.js            # dev-only validation
└── types.d.ts        # internal types

How rendering works

render(component, { props, context, idPrefix }) calls into the compiled server module the compiler emitted for the component. The compiled module is a function that takes a Renderer and pushes content onto it:

sequenceDiagram
    participant U as User code
    participant R as render()
    participant C as Compiled component
    participant Rn as Renderer
    U->>R: render(Component, { props })
    R->>R: create root Renderer + ssr_context
    R->>C: invoke compiled fn(renderer, $$props)
    C->>Rn: push("<div>")
    C->>Rn: push attribute children
    C->>Rn: subordinate children push more strings
    C->>Rn: push("</div>")
    R->>R: await any pending async children
    R-->>U: { html, head, body, css, csp }

The Renderer tracks:

  • A flat list of string segments and child renderers (so async children can flush in-order).
  • The head slot for <svelte:head> content.
  • The css set, populated when inlineStyleSheet is true (default for SSR).
  • The csp nonce list for inline <style> and <script> tags.

renderer.js (~25 KB) implements all of the helpers — attribute, class, style, boolean_attribute, truthy_attribute, merge_props, escape_html, merge_styles. The compiler addresses them by name from generated code.

Attribute and style serialisation

packages/svelte/src/internal/shared/attributes.js provides attr, clsx, to_class, to_style — used both for shouldering CSS framework idioms (clsx) and for normalising server output to match the client. The same helpers are imported by some browser bindings to keep stringification consistent.

Async rendering

Svelte 5 supports async components on the server (the {@async} block, await expressions inside markup). Async branches push promises onto the Renderer queue; index.js awaits them in order before flushing the parent.

blocks/async.js and blocks/await.js are tiny — they exist mostly to format the comment markers correctly for the client to hydrate.

Hydration markers

The compiled server output wraps each block boundary with <!--[--> ... <!--]--> comments. The constants are in packages/svelte/src/internal/server/hydration.js. The matching client-side walker in packages/svelte/src/internal/client/dom/hydration.js reads those markers in lockstep, which keeps server and client structure aligned even when conditional or each-block branches change between requests and hydration.

Context API on the server

context.js exposes the same getContext / setContext shape as the client. There's no proper async-local storage, so context is keyed off a module-level ssr_context stack updated by push/pop. This works because render is single-threaded per call.

CSP (Content Security Policy)

render() returns a csp object containing nonces for any inlined <style> blocks. The renderer accepts a csp option that, if set, applies a nonce attribute and records it in the output. See RenderOutput in packages/svelte/src/internal/server/types.d.ts.

Key source files

File Purpose
packages/svelte/src/server/index.js Public re-export.
packages/svelte/src/internal/server/index.js render() orchestrator (~14 KB).
packages/svelte/src/internal/server/renderer.js The Renderer class (~25 KB).
packages/svelte/src/internal/server/render-context.js Per-render head/css/csp state.
packages/svelte/src/internal/server/blocks/await.js Server-side await block.
packages/svelte/src/internal/server/hydration.js Hydration comment markers.
packages/svelte/src/internal/shared/attributes.js Shared attr / clsx / to_class / to_style.

Entry points for modification

To add a new server-rendered block, mirror the client side: a new visitor under packages/svelte/src/compiler/phases/3-transform/server/visitors/, a helper under packages/svelte/src/internal/server/blocks/, and an export from internal/server/index.js. To change attribute serialisation, edit internal/shared/attributes.js. The client and server runtimes are intentionally kept in sync — attr, clsx, etc. are shared.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Server runtime – Svelte wiki | Factory