sveltekit-advanced
Skill4 starsChanged 55 days agoApache-2.0View on GitHub
SvelteKit 高级功能指南 - 状态管理、远程函数(Remote Functions)、环境变量、Hooks、错误处理、链接选项、Service Workers、服务端模块、快照(快照/Shallow Routing)、$app/* 模块、$lib、$service-worker。
- Reads credentials
In this repository19 other files it gives its agents.
- openspec-apply-changeSkill
- openspec-archive-changeSkill
- openspec-exploreSkill
- openspec-proposeSkill
- svelte-aiSkill
- svelte-awesomeSkill
- svelte-cliSkill
- sveltekit-configSkill
- sveltekit-dataSkill
- sveltekit-overviewSkill
- svelte-legacy-apisSkill
- svelte-lifecycleSkill
- svelte-miscSkill
- svelte-referenceSkill
- svelte-runesSkill
- svelte-runtimeSkill
- svelte-special-elementsSkill
- svelte-stylingSkill
- svelte-template-syntaxSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 4 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 15
Use this skill when you need to:
- Distinctive: line 19
Read env vars safely (private vs public, static vs dynamic).
- Distinctive: line 23
Add a service worker for offline / precaching.
- Very specific: line 26
Use the $app/* modules (forms, navigation, state, paths, server, environment, types).
- Distinctive: line 28
Do NOT use this skill for routing, form actions (legacy), load, basic setup, adapters configuration beyond env vars, or CSS/styling.
- Very specific: line 96
Import from $app/env/private or $app/env/public.
- Very specific: line 151
Place src/service-worker.js (or src/service-worker/index.js) — bundled and auto-registered.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
SvelteKit Advanced
Advanced SvelteKit features reference. Covers state management across server/client, the remote functions API, env vars (legacy and explicit), hooks (server/shared/universal), error handling, link options, service workers, server-only modules, snapshots, shallow routing, and the $app/* modules.
Source: official SvelteKit llms.txt documentation.
When to use this skill
Use this skill when you need to:
- Choose where state lives (server context, URL, snapshot, store).
- Build type-safe client/server RPC with
query/form/command/prerender. - Read env vars safely (private vs public, static vs dynamic).
- Customize request handling via hooks (
handle,handleFetch,handleError,handleValidationError,reroute,transport,init). - Throw expected/unexpected errors, customize the fallback error page, type error shape via
App.Error. - Configure link behavior with
data-sveltekit-*attributes. - Add a service worker for offline / precaching.
- Prevent secret leak via
.server.*or$lib/server/. - Persist ephemeral DOM state with snapshots or route history entries with shallow routing.
- Use the
$app/*modules (forms,navigation,state,paths,server,environment,types).
Do NOT use this skill for routing, form actions (legacy), load, basic setup, adapters configuration beyond env vars, or CSS/styling.
Critical sections
1. State management
- No shared server state — module-level variables (
let user;) leak across requests. Authenticate via cookies, persist to DB. - Pure
loadfunctions — no side effects (no global stores). Return data instead. - Context for per-request state —
setContext('user', () => data.user)(pass a function so reactivity crosses boundaries). Reading context updated during SSR in a child does NOT propagate to the parent (it has already rendered). - Component state is preserved across nav —
constderived fromdataonly computes once. Use$derived(...)for values that should recompute when data changes. - URL state — search params for filters/sort; survives reload, affects SSR.
- Snapshots — disposable UI state (e.g., "is accordion open?") bound to history entry.
2. Remote functions (since 2.27, experimental)
Opt in via svelte.config.js:
kit: { experimental: { remoteFunctions: true } },
compilerOptions: { experimental: { async: true } }Flavors exported from *.remote.js:
| Flavor | Purpose | Key features |
query | Read dynamic server data | Dedup, refresh(), loading/error/current |
query.batch | Batch n+1 queries in one call | Returns (input, idx) => Output |
query.live | Real-time async iterable | connected, reconnect(); first value serialized for SSR |
form | Progressive-enhanced <form> | <form {...createPost}>, createPost.fields.x.as('text'), validate(), enhance(), for(id), preflight(schema) |
command | Imperative mutation from event handlers | Cannot be called during render |
prerender | Build-time data | inputs, dynamic: true |
- Validate with any Standard Schema (Zod/Valibot).
- Args/returns serialized via devalue.
getRequestEvent()works inside remote functions for cookies.redirect(...)allowed inquery/form/prerender, NOT incommand.- Single-flight mutations:
getPosts().refresh()orgetPost(id).set(...)in server handler;requested(getPosts, 1).refreshAll()for client-requested refreshes (limit is DoS protection).
3. Environment variables
Legacy $env/* (default before SvelteKit 2.63):
| Module | Scope | Timing |
$env/dynamic/private | Server only | Runtime (process.env-like) |
$env/dynamic/public | Public (PUBLIC_*) | Runtime |
$env/static/private | Server only | Build time (inlined) |
$env/static/public | Public | Build time (inlined) |
Explicit env vars (opt-in, default in v3):
Enable in svelte.config.js: kit.experimental.explicitEnvironmentVariables = true. Then create src/env.ts:
import { defineEnvVars } from '@sveltejs/kit/hooks';
import * as v from 'valibot';
import { building } from '$app/env';
export const variables = defineEnvVars({
API_KEY: {}, // private
GOOGLE_ANALYTICS_ID: { public: true }, // public
SHOW_DEBUG_OVERLAY: { public: true, static: true }, // inlined, dead-code-eliminated
SECRET: { schema: building ? v.optional(v.string()) : v.string() },
CACHE_TTL_SECONDS: { description: 'How long...' }
});Import from $app/env/private or $app/env/public. $app/environment is renamed to $app/env.
4. Hooks
Three optional files: src/hooks.server.js, src/hooks.client.js, src/hooks.js.
Server (hooks.server.js):
handle({ event, resolve })— runs on every request; return Response or callresolve(event, opts).resolveopts:transformPageChunk,filterSerializedResponseHeaders,preload. Usesequence(...)for multiple.handleFetch({ request, fetch, event })— rewrite cross-origin requests to internal APIs; cookie forwarding for sibling subdomains.handleValidationError({ event, issues })— customize 400 response for bad remote function args.
Shared (hooks.server.js AND hooks.client.js):
handleError({ error, event, status, message })— for unexpected errors only. Return{ message, ... }-> becomespage.error. Must never throw. Server type:HandleServerError; client type:HandleClientError; clienteventisNavigationEvent.init()— runs once at startup; useful for DB connections.
Universal (hooks.js):
reroute({ url, fetch })— translate URL to a different route (e.g., i18n). Pure/idempotent. Can be async since 2.18.transport— custom encoders/decoders for types crossing the server/client boundary (e.g.,Vector).
5. Errors
- Expected errors —
error(404, 'Not found')(orerror(404, { message, code })) from@sveltejs/kit. Renders nearest+error.svelte, sets status code.page.error= the object passed. - Unexpected errors — any other exception. Not exposed (generic
Internal Error); routed throughhandleError. - Rendering errors — opt in via
experimental.handleRenderingErrors. Error passed directly to+error.svelteaserrorprop (not viapage.error). - Responses — custom
src/error.htmlwith%sveltekit.status%and%sveltekit.error.message%. Errors in root+layout.server.jsuse fallback page (root contains+error.svelte). - Type safety — declare
App.Errorinterface insrc/app.d.ts:
declare global {
namespace App {
interface Error { message: string; code: string; id: string; }
}
}6. Link options
data-sveltekit-* attributes on <a> (or parent). Also apply to <form method="GET">.
| Attribute | Values | Effect |
preload-data | hover (default), tap | Preload load data on hover/tap |
preload-code | eager, viewport, hover, tap | Preload route code only |
reload | boolean | Force full-page nav (also rel="external") |
replacestate | boolean | Replace history entry instead of push |
keepfocus | boolean | Keep focus on the same element after nav |
noscroll | boolean | Disable scroll-to-top after nav |
Disable in subtree with data-sveltekit-preload-data="false". Respects navigator.connection.saveData.
7. Service workers
Place src/service-worker.js (or src/service-worker/index.js) — bundled and auto-registered. Disable via config to register manually.
Available from $service-worker: base, build, files, prerendered, version.
Standard pattern: cache build + files on install, network-first with cache fallback on fetch. Skip responses with Cache-Control: no-store (live queries). build/prerendered are empty arrays in dev.
8. Server-only modules
$env/static/privateand$env/dynamic/private— server-only.$app/server— server-only.- Your modules — add
.server.jssuffix OR place under$lib/server/.
Illegal imports from browser code error at build. Use import type for type-only. Detection is disabled in tests (process.env.TEST === 'true').
9. Snapshots & shallow routing
Snapshots — export snapshot = { capture, restore } from +page.svelte or +layout.svelte. Captured to sessionStorage before page updates; restored on history nav. Must be JSON-serializable. Don't return huge objects.
Shallow routing — pushState(url, state) / replaceState(url, state) create history entries without navigating. Read via page.state. Use preloadData(href) to grab load data, then pushState(href, { selected: result.data }) to render another +page.svelte inside a modal. page.state is always {} on first SSR and during first paint.
Quick Fixes
| Symptom | Fix |
| User data leaks between requests | Don't use module-level vars; use cookies + DB |
load data not updating on nav | Use $derived(...) not const for values derived from data |
Cannot import $lib/server/... | Move shared types to import type |
| Live query stream stops | Reconnect with .reconnect(); don't cache no-store responses in SW |
error(404, ...) shows blank page | Add +error.svelte nearest to the route |
| Server-only env leaked to client | Use $env/static/private or .server naming |
| Validation 400 generic message | Implement handleValidationError |
| Component state lost on nav | Wrap with {#key page.url.pathname}<X/>{/key} to force remount |
Gotchas
loadmust be pure — no global store writes. Return the data instead.- Context updates during SSR don't propagate up — pass state down to avoid flash on hydration.
query.batchreturns a single function that maps individual inputs to outputs; not a direct array of results.query.liveon SSR returns ONLY the first yielded value then closes.commandcannot be called during render — invoke from event handlers.requestedrequires alimit— DoS protection; passInfinityonly if explicitly safe.error()no longer needsthrowin SvelteKit 2.x.page.stateis{}on SSR and first paint — don't rely on it for critical render.reroutemust be pure/idempotent — its result is cached per URL on the client.- Service worker
build/prerenderedempty in dev — test in production build. - Cookie forwarding for sibling subdomains requires manual
handleFetch— SvelteKit can't tell which parent-domain cookie belongs to which subdomain. handleErrormust not throw — wrap risky work in try/catch.
FAQ
Q: $app/state vs $app/stores?
A: $app/state (since 2.12) is rune-based and reactive. $app/stores is the legacy store-based version. Use $app/state with Svelte 5.
Q: query vs prerender?
A: query for dynamic data; prerender for build-time-frozen data that can be served from a CDN. query cannot be used on a fully prerendered page.
Q: form vs command?
A: form is progressive-enhanced — works without JS, spreads onto <form>. command is JS-only, called from event handlers. Prefer form.
Q: $env/dynamic vs $env/static?
A: dynamic reads at runtime (e.g., process.env); static inlined at build time (enables dead-code elimination). Use static for build-time-known values.
Q: $env/static/private vs $env/dynamic/private?
A: Same access restriction; difference is when the value is read. Static gives DCE; dynamic allows runtime override (e.g., MY_FLAG=1 npm run dev).
Q: Can I use $lib/server modules from +page.svelte? A: No — server-only modules cannot be imported by client code, transitively. SvelteKit errors at build.
Q: How do I keep focus on a search input after submit?
A: Add data-sveltekit-keepfocus to the <form>.
Q: How do I throw a 404 from a load?
A: import { error } from '@sveltejs/kit'; error(404, 'Not found'); (don't throw in SvelteKit 2).
Q: Should I use Sentry?
A: Yes — initialize in handleError of both hooks.server.js and hooks.client.js. Server uses HandleServerError; client uses HandleClientError with NavigationEvent.
Examples
| Topic | File |
| State management with context + URL + derived | examples/state-management.md |
| Remote query/form/command/batch/live | examples/remote-functions.md |
| Env vars (legacy + explicit) | examples/env-vars.md |
| Server + universal hooks | examples/hooks.md |
| Expected/unexpected errors + App.Error | examples/errors.md |
| data-sveltekit-* link options | examples/link-options.md |
| Service worker precache + offline | examples/service-worker.md |
| $app/* modules (forms, navigation, state, paths, server) | examples/app-modules.md |
| Snapshots + shallow routing | examples/shallow-snapshots.md |
References
| Topic | File |
| State management | references/state-management.md |
| Remote functions | references/remote-functions.md |
| Environment variables | references/env-vars.md |
| Hooks | references/hooks.md |
| Errors | references/errors.md |
| Link options | references/link-options.md |
| Service workers | references/service-worker.md |
| Server-only modules | references/server-only.md |
| $app/* modules | references/app-modules.md |
| Snapshots & shallow routing | references/shallow-snapshots.md |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

