Svelte Knowledge Patch
Use this patch when writing, reviewing, upgrading, or troubleshooting Svelte and SvelteKit applications. Start with the migration notes, then read every topic reference relevant to the code being changed.
Reference index
| Reference | Topics |
|---|---|
| SvelteKit routing and runtime | Error boundaries, paths, typed route parameters, navigation, prerendering, environment guards, CSP, service workers, rerouting, and instrumentation |
| Remote forms | Deep-partial values, schemas, preflight, submission and reset state, validation issues, redirect targets, and streamed uploads |
| Remote queries and commands | Optional inputs, URL context, explicit awaiting, refreshes, invalidation, cache policy, transport errors, and live reconnects |
| Runes and components | Dependency tracking, state and props, stable IDs, attachments, snippets, template declarations, contexts, and asynchronous rendering |
| Svelte 5 migration | Staged dependency and syntax migration |
| Tooling, build, and deployment | Clientless and inline builds, precompression, generated typings, Vite, CLI scaffolding, configuration, TypeScript, CSP hydration, Cloudflare, and Deno |
Migration and behavior changes
Upgrade in stages
Move a Svelte 3 application to Svelte 4 before adopting Svelte 5. Then update
svelte and related packages such as vite-plugin-svelte. Existing component
syntax can coexist with Svelte 5, and application upgrades do not need to wait
for every component dependency to migrate.
Run the optional syntax migration only after the dependency upgrade:
npx sv migrate svelte-5
Read Svelte 5 migration before changing an older application.
Await remote calls explicitly
A remote function call in a template does not delay rendering merely because it
was invoked. Add await when its completion must gate output:
<p>{await getSummary()}</p>
Do not rely on implicit blocking. See Remote queries and commands.
Track reactive reads precisely
- Treat reactive reads after an
awaitwritten directly in$derived(...)as dependencies. Reads hidden in a called helper are not covered by that rule. - Expect
$effectto subscribe only to values read synchronously during its latest execution. Reads afterawaitor in timers are not tracked. - Read a proxy property, not just the proxy object, when an effect must react to that property's mutations.
- Do not expect destructuring from a
$stateproxy to stay reactive. - Do not expect
$derivedresults to be deep-proxied.
Preserve state ownership
A fallback object supplied while destructuring $props() is an ordinary object,
not a state proxy. Mutating parent-owned state can update the parent, but warns
unless the prop is explicitly bindable. Design child-to-parent writes as bindings
or callbacks instead of silently mutating ownership.
Class fields initialized with $state compile to non-enumerable accessors. Do
not serialize or spread such instances expecting those fields to appear; expose
serializable values explicitly.
Treat prerender conflicts as build errors
- A prerendered root
+server.jsmust return HTML. - A prerenderable route containing both
+pageand+serveris ambiguous and fails early; pages otherwise take precedence during prerendering. - Configure
prerender.handleInvalidUrlfor malformed crawl targets.
Account for navigation ordering
During navigation, SvelteKit blurs the active element before updating the
component. blur and focusout handlers therefore see outgoing data. Snapshot
restoration happens after afterNavigate callbacks.
Recheck generated and build configuration
Generated TypeScript configuration no longer injects types: ['node']. Add Node
types yourself only when project code needs them. Preserve explicit Vite 8
codeSplitting; SvelteKit no longer replaces it unnecessarily.
If the root route tree sets csr = false, SvelteKit can omit the client build
entirely. Do not assume client artifacts exist in a fully server-rendered build.
Runes and component quick reference
Coordinate asynchronous UI
Use $effect.pending() to count promises pending in the current boundary; child
boundaries are excluded. Use $state.eager(value) for immediate feedback that
must not wait for synchronized asynchronous updates.
{#if $effect.pending()}
<p>Saving…</p>
{/if}
<a aria-current={$state.eager(pathname) === '/' ? 'page' : null} href="/">
Home
</a>
Use derived state for optimistic UI
A $derived binding declared with let can be reassigned. Its optimistic value
lasts until a dependency changes and the derived expression recalculates.
<script>
let { post } = $props();
let likes = $derived(post.likes);
const like = () => likes += 1;
</script>
Destructuring directly from $derived(...) creates individually reactive
bindings:
let { a, b } = $derived(makeValues());
Generate hydration-stable IDs
Use $props.id() for component-instance IDs shared by server rendering and
hydration:
<script>const uid = $props.id();</script>
<label for="{uid}-name">Name</label>
<input id="{uid}-name" />
Prefer attachments for element lifecycle behavior
Apply an attachment with {@attach ...}. It receives the mounted element and
may return cleanup logic:
<script>
const autofocus = (node) => {
node.focus();
return () => {};
};
</script>
<input {@attach autofocus} />
Adapt an existing action with fromAction. For parameterized actions, pass a
function that returns the argument. Library-authored spread props can attach
behavior with the symbol from createAttachmentKey().
Respect snippet constraints
Snippet parameters support defaults and destructuring, but not rest parameters.
Top-level snippets can be exported from <script module> when they have no
direct or transitive dependency on instance-script declarations. Use
createRawSnippet only for programmatic snippet construction.
Template scope also accepts let and const declaration tags, including
multiple declarators whose later initializers refer to earlier ones:
{let count = $state(0), doubled = $derived(count * 2)}
<button => count++}>{doubled}</button>
Read Runes and components for complete tracking, ownership, attachment, snippet, and asynchronous-rendering details.
SvelteKit remote-data quick reference
Type remote inputs and form values narrowly
Remote query, command, and prerender inputs may be optional when their
declared type allows omission. Remote form .value() and .set(...) accept
deep-partial nested shapes. Optional schema fields work with
exactOptionalPropertyTypes.
Model checkbox-like boolean fields as optional when unchecked HTML controls are omitted. Empty file inputs are likewise omitted from remote form payloads.
Refresh and consume remote results safely
Remote queries can refresh related queries. Navigation with invalidateAll
resets remote query state before the next route begins. Failed calls are safely
consumed by reading current or error; transport failures preserve their HTTP
status and body.
Remote responses use cache-control: private, no-store. Do not put personalized
results in shared caches by overriding that policy casually.
Drive form UI from built-in state
Use a remote form's submitted property rather than duplicating submission
state. Resetting a form clears issues and touched fields. Branch-level
issues() returns undefined when only a descendant field has an issue.
Read Remote forms and Remote queries and commands before implementing remote data flows.
Routing, runtime, and deployment quick reference
- Pass query and hash suffixes through
$app/paths.resolve(). - Rely on matcher-narrowed route parameters in
$app/types,$app/state, and hooks rather than recasting them. - Call
preloadCodeduring initial loading when early route-code fetches help. - Guard runtime-only environment validation with
buildingfrom$app/environment. - Include
ws:,wss:, andtrusted-types-evalin CSP source lists when the application policy requires them. - Use
$service-worker'sbasein development as well as production. - Initialize server observability from
instrumentation.server.ts; SvelteKit can emit OpenTelemetry traces. - Expect support for asynchronous rerouting, streamed form uploads, CSP-compatible hydration, automatic Cloudflare adapter setup, and Deno.
Read SvelteKit routing and runtime and Tooling, build, and deployment before changing adapters, build output, runtime hooks, or security policy.