Svelte deep knowledge
Use this as an index of likely knowledge gaps. Verify the relevant APIs against the official Svelte MCP during planning and implementation.
Verified on 2026-11-01 against Svelte 5.57.3, SvelteKit 3.1.1, and SvelteKit 2.70.3.
Start with the installed versions
- Inspect the package versions and Vite configuration. Match guidance to the installed Kit major version and the enabled experimental flags.
- Call the Svelte MCP's
list-sections, then fetch the relevant sections together withget-documentation. The MCP and svelte.dev serve Kit 3 docs. For a Kit 2 project, read the matching page from theversion-2branch ofsveltejs/kitunderdocumentation/docs. - For Kit 3 projects and Kit 2 → 3 migrations, read the Kit 3 reference. For Kit 2 projects, read the Kit 2 reference.
- Run
svelte-autofixeron new or edited Svelte components/modules and resolve applicable findings. Use the project's checks for integration and types.
For examples of new Svelte APIs, async rendering, attachments, and compiler tooling, read the Svelte reference.
Remote functions, boundaries, and await
For new SvelteKit apps adopting experimental async, prefer remote functions with direct await for component data and granular boundaries for loading/error UI. Choose svelte:boundary placement based on what must render on the server.
- Enable
experimental.remoteFunctionsandcompilerOptions.experimental.asynctogether. The official remote-functions setup requires both flags. load, form actions, and+serverroutes remain supported but not encouraged. Follow existing architecture unless the task includes migration..loading,.error, and.currentremain supported query APIs. Directawaitis the preferred mechanism.- Use
await query(args)in rendering and imperative contexts. {#await}remains supported though not encouraged, and has its own promise-state behavior. Use direct await and boundaries for coordinated async rendering; preserve{#await}when its behavior fits the task.
Verify with MCP sections kit/remote-functions, svelte/await-expressions, and svelte/svelte-boundary.
Async rendering behavior
- Component-level await arrived in Svelte 5.36; async SSR arrived in 5.39. Await is supported in the top-level script,
$derived, and markup. - Svelte coordinates dependent UI updates while async work resolves. Independent template await expressions run concurrently. Sequential script awaits still create waterfalls; start independent work before awaiting its results.
- A boundary's
pendingsnippet appears on initial creation. Use$effect.pending()for subsequent work in that boundary; its count excludes child boundaries. - During SSR, a boundary with
pendingrenders the placeholder and skips its content. Await expressions outside such boundaries resolve beforeawait render(...)completes. Place content needed in the initial HTML accordingly. This API does not yet provide streaming SSR. $state.eager(value), added in 5.41, exposes immediate feedback while coordinated updates wait. Use it for user feedback such as an active navigation indicator.tick()waits for pending state changes;settled(), added in 5.36, also waits for async work caused by them and the resulting DOM updates.
Error boundaries
<svelte:boundary>supportsfailed(error, reset)andonerror(error, reset)for rendering/effect failures. Handle event-handler and detached async errors at their call sites.failedsnippets also catch errors during SSR, since Svelte 5.53. In SvelteKit, the error goes throughhandleErrorfirst, so the snippet receives the sanitizedApp.Error.onerrorruns when the failed boundary hydrates.- Kit 3 sends rendering errors through
handleErrorto the nearest+error.svelte, which acts as a boundary. An async clienthandleErrorneedscompilerOptions.experimental.async. Kit 2.54+ needsexperimental.handleRenderingErrorsfor the same integration. - The boundary documentation's older “since 5.51” note conflicts with the published changelog. Use 5.53 as the introduction version and check current patches when diagnosing SSR/hydration issues.
Template features
Declaration tags, Svelte 5.56+
- Prefer
{let ...}and{const ...}for markup-local variables.{@const}is documented as legacy and remains available for older projects. - Plain declarations initialize values. Use explicit runes for reactivity:
{let count = $state(0)}and{const doubled = $derived(count * 2)}. - Migrating reactive
{@const area = width * height}requires{const area = $derived(width * height)}. A plain{const area = width * height}is not reactive. - Declarations use lexical scope within their element/block, can shadow outer variables, and should precede use. Multiple declarators are supported.
Attachments
- Prefer
{@attach ...}for new element integrations on Svelte 5.29+. Return cleanup from the attachment. - Attachments track reactive reads and re-run when dependencies change. Falsy values disable them. Avoid repeating expensive setup by reading changing options through a getter inside a child effect.
- Component wrappers must forward attachment-bearing props to the intended element.
createAttachmentKey()supports attachments in spread objects. fromAction(action, () => argument)preserves an existing action's behavior. Its second argument is a getter. This helper arrived in 5.32, after attachments themselves.
Classes, bindings, and HTML
classaccepts nested arrays and objects since 5.16.ClassValuefromsvelte/elementsis available since 5.19 for wrapper props.- Function bindings use
bind:value={get, set}since 5.9. Usenullas the getter for readonly bindings. - Numeric inputs may produce
undefinedwhen empty or invalid. Checkbox state can usebind:checkedandbind:indeterminate; radio groups usebind:group. - Inputs support
defaultValue/defaultCheckedsince 5.6. Selects supportdefaultValuesince 5.57, including form reset behavior. Check binding precedence when supplying defaults. - Customizable native selects are supported since 5.47. Check browser support and the documented
<selectedcontent>pattern before replacing a custom select widget. - JavaScript-style comments between attributes are valid since 5.53:
<div /* explanation */ class="card">. {@html}acceptsTrustedHTMLsince 5.52. Trusted Types support does not sanitize arbitrary input; use a trusted source or sanitization policy.
Each blocks and snippets
{#each items as { id, name }}destructures items. Range iteration can use{#each { length: 8 }, index}.- Prefer stable item keys for lists whose identity matters. When editing an item, bind its property through the item object so mutations reach the source.
- Snippets are declared in markup and rendered with
{@render snippet(...)}. Top-level snippets can be exported from<script module>since 5.5 if they do not capture instance state. - Snippets support generics since 5.30. Component generics use
<script lang="ts" generics="T">. - In runes mode, component variables render dynamically as
<Component />. Recursive components can import themselves.
Runes and shared state
State and props
$state.rawtracks reassignment without deep proxying. Use it for large values replaced as a whole.$state.snapshotextracts plain data and respectstoJSON().- Class instances are not deeply proxied. Use
$statefields, or their first constructor assignment since 5.31. Reactive fields become non-enumerable accessors; preservethiswhen passing methods as callbacks. - Passing a reactive value to a function passes its current value. Pass a getter when the function needs future values. Destructuring a proxy also reads current values.
- Use
.svelte.js/.svelte.tsfor shared rune logic. Export a stable state object or accessors when consumers need changing state; directly exporting reassigned rune state is restricted. - Scope user-specific state through component context during SSR. Shared module state can leak across requests.
$props.id(), added in 5.20, gives a component-instance ID that matches between SSR and hydration.$bindable()declares a bindable prop. Props can be locally reassigned; mutating a parent's non-bindable proxy raises ownership warnings. Fallback values are not automatically proxied.- Keep the actual uninitialized type of
$state<T>(), which includesundefined, or provide a valid initial value. Use narrowing at access sites.
Deriveds and effects
- Use
$derived(expression)or$derived.by(fn)for computed values. Deriveds declared withletcan be reassigned for optimistic UI since 5.25; dependency changes recompute them. - Destructured
$derivedvalues stay reactive. Returned objects are not automatically deep proxies. Referential equality can skip downstream work. - Effects track synchronous reads from their latest run. Reads inside an ordinary async callback after await are not automatically dependencies.
$effectruns in the browser. Return cleanup synchronously; reserve effects for external synchronization and put user-triggered work in handlers.$effect.tracking()detects a tracking context.$effect.root()creates a manually managed scope and returns a disposer.getAbortSignal(), added in 5.35, must run inside an effect or derived. Its signal aborts on re-execution or destruction. Use it for fetch work owned by that reactive computation.untrack(fn)excludes reads from dependency tracking.$inspect(...).with(fn)receives"init"/"update"followed by values.$inspect.trace(label?), added in 5.14, must be the first statement in the traced function.$host()is for custom elements and returns their host DOM element.
Runtime modules
createContext<T>()provides typed context since 5.40. Since 5.57 it returns[get, set, has];has()checks availability beforeget(), which throws when unset. Context lookup includes the current component and ancestors. Call context accessors during initialization, and set context before the firstawaitin the script. Since 5.57.1, a latersetContextthrowsset_context_after_initduring SSR.svelte/reactivityprovidesSvelteMap,SvelteSet,SvelteDate,SvelteURL, andSvelteURLSearchParams. Map/Set entries are not made deeply reactive.- Svelte 5.57 adds
SvelteMap.getOrInsert(key, value)andgetOrInsertComputed(key, key => value). The computed callback runs when the key is absent, including correct handling of existingundefinedentries. MediaQueryandcreateSubscriberarrived in 5.7. UsecreateSubscriberto connect external events to tracked reads with shared subscription setup and cleanup.MediaQueryaccepts an SSR fallback; use CSS when it can express the same behavior.svelte/reactivity/windowprovides reactive.currentvalues for dimensions, scroll position, online status, screen position, and pixel ratio since 5.11. Account for unavailable window values during SSR.on()fromsvelte/eventspreserves ordering with declarative event handlers and returns cleanup. Use<svelte:window>/<svelte:document>for declarative global listeners.flushSync(fn?)flushes pending updates synchronously.createRawSnippetsupports programmatic markup with setup/cleanup.getAllContexts()supplies the current context map for programmatic mounting; call it during initialization.SpringandTweenfromsvelte/motionreplace deprecatedspring()/tweened()stores since 5.8. Both expose.target,.current,.set(), and.of(fn).Spring.setsupportspreserveMomentum;prefersReducedMotionsupports accessible motion.- Since 5.55, motion exports include
TweenOptions,SpringOptions,SpringUpdateOptions, andUpdater. hydratable(key, fn), added in 5.44, serializes data for reuse during hydration. It uses devalue and supports nested promises. Namespaced keys avoid collisions. Kit remote functions already handle this layer.- With CSP, custom SSR integrations must configure
renderwith a nonce per response or static hashes and put matching values in the response headers. Svelte 5.46 added render CSP support; 5.57 exportsRenderOutput,SyncRenderOutput,Csp, andSha256Sourcefromsvelte/server. - For tooling,
print()converts a modern Svelte AST to source since 5.45;parseCss()arrived in 5.48. Compiler optionscss,runes, andcustomElementcan be filename-dependent functions since 5.54. Read the Svelte reference before using these APIs.
SvelteKit
New apps use Kit 3 (npx sv create). Migrate a Kit 2 app with npx sv migrate sveltekit-3, then work through the generated TODOs. Kit 2 guidance applies only to projects that stay on 2.x.
Kit 3 baseline
- Kit 3 requires Node 22.17, TypeScript 6, Svelte 5.57.1, Vite 8.0.12, and vite-plugin-svelte 7.
- Configuration lives in
sveltekit({...})insidevite.config.ts, with Kit options at the top level besidecompilerOptions. Kit 3 no longer readssvelte.config.js. #libreplaces$libthrough package.json subpath imports. Write file extensions, such as#lib/server/db.ts.- A
serverfilename segment, or anyserverdirectory outsidesrc/routes, marks a module server-only. Aremotefilename segment, as indata.remote.tsorremote.ts, marks a remote module. - Declare environment variables in
src/env.tswithdefineEnvVarsfrom@sveltejs/kit/env. Import values from$app/env/privateand$app/env/public, andbrowser,building,dev,versionfrom$app/env. Public variables can appear inapp.htmlas%sveltekit.env.NAME%.$env/*and$app/environmentare deprecated aliases. $app/storesis removed; use$app/state.page.urlis readonly; copy it withnew URL(page.url.href)before editing.$app/pathsexportsresolve,asset, andmatch;base,assets, andresolveRouteare removed. GeneratedPathandAssetPathtypes omit the leading slash.- Define param matchers in one
src/params.tswithdefineParamsfrom@sveltejs/kit/params. A matcher is a function or a Standard Schema, and its output types the param. - Remote function types live in
$app/server, navigation types in$app/navigation,Page/ReadonlyURLin$app/state,ActionResult/SubmitFunctionin$app/forms, and hook types in@sveltejs/kit/hooks.RequestEventandCookiesstay in@sveltejs/kit. json()andtext()are deprecated; useResponse.json(...)andnew Response(...).
Kit 3 navigation, errors, and deployment
- Shallow routing uses
goto(url, { shallow: true, state });pushState/replaceStateare deprecated. Addreplace: trueto replace the entry andpersistState: trueto keeppage.stateafter reload.reset: falsereplacesnoScrollandkeepFocus. Navigation hooks fire for shallow changes too; checknavigation.shallow. refreshAll()takes no options and keepspage.state;invalidateAll()is deprecated. A click on a link to the current URL runsrefreshAll().gotorejects destinations outside the app; usewindow.location.hreffor those.preloadDatacan return{ type: 'error' }.preloadCodetakes a route ID such as/blog/[slug].- Call
snapshot({ capture, restore, id, reset })from$app/navigationduring component initialization. It replacesexport const snapshot. handleErrorreceives every error with akind:'app','framework','validation'(server only), or'unknown'. Returnstatusto change the response status. It replaceshandleValidationError.App.Erroralways includesstatus; pass extra fields aserror(status, message, details).redirectto another origin needs{ external: true }or an origin allowlist.- Enable tracing with top-level
tracing: { server: true }.src/instrumentation.server.tsloads automatically, after env vars are populated. - Set
paths.originwhen request headers cannot give the public origin, for example behind a proxy. It replacesprerender.originand adapter-node'sORIGINvariable. version.pollIntervaldefaults to one hour.updated.currentalso turns on after server data loads, remote calls, and tab focus.- adapter-cloudflare 8 removes
platform: importenvandwaitUntilfromcloudflare:workers, readrequest.cf, and use the globalcaches. adapter-vercel drops the edge runtime.@sveltejs/adapter-bunserves the app with Bun 1.4+.
Remote functions, experimental since 2.27
Define remote functions in files with a remote filename segment and import query, form, command, or prerender from $app/server. Validate untrusted input with a Standard Schema implementation and authorize access in the handler.
queryreads data;query.batchbatches calls made in the same macrotask. Reuse awaitable query instances and verify cache/subscription lifetime for imperative consumers.- In Kit 3, reading
event.url,event.params, orevent.routeinside a query throws. Pass route values as arguments. query.live, added in 2.59, yields current data from an async generator. It exposes.connectedand.reconnect()and supportsfor awaitsince 2.61. Consumers share a connection and intermediate values can be coalesced. Use it for current state, not an event log. Live queries update themselves instead of using.refresh().formsupports progressive enhancement through spread attributes, typed.fields, field.as(...), validation issues,.preflight(),.validate(),.enhance(), and.for(id)for independent instances. Fields starting with_are not repopulated after failure. Kit 3 rejects submissions from controls not created withfield.as(...).- Since 2.56,
field.as(type, defaultValue)supports defaults. In Kit 3, radio and checkbox options take the checked state third:.as('checkbox', tag, tags.includes(tag)). Since 2.57, enhancedsubmit()resolves to a validity boolean. Check it before clearing input or performing success-only UI actions. - Since 2.69,
form.submittedis a boolean indicating whether the form has been submitted at least once; Kit 3 clears it on reset.form.resultbecomes available after the handler returns;form.pendingcounts in-flight submissions. - Kit 3 fields have
touched()anddirty(). Kit 3 usesvalidate({ all: true })where Kit 2 usesvalidate({ includeUntouched: true }); the 3.1 docs page still shows the Kit 2 name, so trust the installed types. - Since 2.68,
RemoteFormEnhanceInstanceandRemoteFormEnhanceCallbackprovide types for reusable enhancement wrappers. commandperforms imperative mutations. Invoke it from user interactions or other appropriate imperative code; calling commands during rendering is disallowed. Prefer a remote form for a natural HTML form workflow.prerenderproduces build-time data, supports enumeratedinputsanddynamic: true, and can use the browser Cache API. Check its public-data and caching constraints.
Refreshes and validation
- Single-flight updates combine mutation results and refreshed data in one response. Server handlers can use
query(args).refresh()or.set(data); queries can update other queries since 2.65. - Client-requested
.updates(...)require server cooperation.requested(queryFunction, limit)yields{ arg, query }, plusignorein Kit 3; the bound query preserves the original cache key even if validation transformsarg. Supply the required limit and update those bound queries.query.batchis supported; live queries use reconnect APIs..withOverride(fn)adds an optimistic value to a requested update. - In Kit 3, the server must refresh, set, reconnect, or
ignore()every requested update within the limit; otherwise that query errors on the client.requested(...).refreshAll()and.ignoreAll()handle the whole list. invalid()reports programmatic field issues. Invalid remote calls reachhandleErrorwithkind: 'validation'in Kit 3 andhandleValidationErrorin Kit 2.getRequestEvent()exposes request context; follow its async-context constraints on the target runtime.- Use the reference for the installed Kit version for full form, live-query, and refresh examples before implementing these experimental APIs.
Routing, state, and hooks
$app/state, added in 2.12, exposes rune-reactivepage,navigating, andupdatedobjects.$:does not track their updates. Usepage.statefor shallow-routing state.resolve, added in 2.26, resolves a pathname or a typed route ID plus params.asset()resolves static assets.match(), added in 2.52, resolves a pathname back to a route ID and params.- Generated
$app/typesincludesRouteIdandRouteParams, plusPathnamein Kit 2 orPath,PageRouteId, andEndpointRouteIdin Kit 3. Parameter matchers narrow generated parameter types since 2.55. onNavigatecan await a view transition and return a callback for after the DOM update. Navigation targets expose scroll positions since 2.51.preloadCodeloads route code without running load functions.transportis a universal hook for custom serialization; Kit 3 also uses it forpage.stateand snapshots.csrf.trustedOriginscontrols cross-origin form submissions.output.bundleStrategyacceptssplit,single, andinline.csp.modeacceptshash,nonce, andauto.prerender.handleInvalidUrl, added in 2.67, handles malformed URLs found while crawling;handleHttpErrorhandles HTTP failures separately.
Kit 2 projects
Kit 2.70.3 is the final 2.x release. Read the Kit 2 reference before writing Kit 2 configuration, environment, or navigation code.
- Configuration lives under
kitinsvelte.config.js. Since 2.62 it can also be flattened intosveltekit({...}), which makes Kit ignoresvelte.config.js. Follow the shape the project uses. - Environment variables use
$env/static/*,$env/dynamic/*, and$app/environment.experimental.explicitEnvironmentVariables, added in 2.63, opts into the Kit 3 model; since 2.70,defineEnvVarscomes from@sveltejs/kit/env. - Shallow routing uses
pushState/replaceStatewithpreloadData. Snapshots useexport const snapshotwithcapture/restore, typed asSnapshot<T>. gotoacceptsnoScroll,keepFocus, and aninvalidatearray of strings, URLs, or(url: URL) => booleanpredicates.refreshAll({ includeLoadFunctions })refreshes queries and loads; passfalseto skip loads.invalidateAll()reruns active-page loads and queries.handleErrorskips expected errors. Tracing usesinstrumentation.server.tswith the experimental tracing and instrumentation flags, added in 2.31.
TypeScript and component conventions
- Use
Component<Props>,ComponentProps<typeof Component>, andSnippet<[Arguments]>for component APIs. Element wrappers can useHTMLButtonAttributesorSvelteHTMLElements['div']fromsvelte/elements. - Augment
svelte/elementsfor custom attributes/events. Native TypeScript support covers syntax that erases; features needing runtime transformation require preprocessing. - In new runes components, use
$props, callback props, event attributes, snippets, and$derived. Preserve legacy syntax when maintaining a legacy component unless migration is part of the task. - Use CSS custom properties for parent-controlled child styling. Prefer
.svelte.tsstate classes and typed context for new shared reactive logic; retain store contracts where integrations require them.
Maintaining this skill
Review the complete package changelogs, recent official monthly posts, and MCP examples. Check the published types when docs and changelog disagree. Follow later reversals of experimental changes before recording an API. Update the verified date and version scope, and keep detailed usage in the linked references.
Release sources: Svelte changelog, Kit 3 changelog, Kit 2 changelog, and official posts.