svelte-sveltekit-engineering
Skill11 starsChanged 11 days agoMITView on GitHub
Svelte and SvelteKit engineering guidance. Use when adding, changing, reviewing, or testing .svelte components, Svelte 5 runes, stores, context, SvelteKit routing, load functions, form actions, hooks, adapters, or deciding between standalone Svelte and full SvelteKit. Use javascript-typescript-engineering for generic JS/TS package/build/test mechanics, css-scss-styling for stylesheet and Tailwind decisions, api-design for backend contract shape, and ux-accessibility-review for accessibility audits. Do not use for non-Svelte frontend frameworks.
In this repository70 other files it gives its agents.
- AGENTS.mdAGENTS.md
- adversarial-reviewSkill
- api-designSkill
- architecture-reviewSkill
- behavior-driven-developmentSkill
- brainstormingSkill
- ci-release-engineeringSkill
- clean-architectureSkill
- code-reviewSkill
- container-engineeringSkill
- create-agent-skillSkill
- csharp-dotnet-engineeringSkill
- css-scss-stylingSkill
- data-platform-engineeringSkill
- dependency-supply-chain-reviewSkill
- digital-asset-managementSkill
- documentation-engineeringSkill
- domain-driven-designSkill
- domain-modelingSkill
- donsetch-web-researchSkill
- gherkinSkill
- git-commitSkill
- git-workflowsSkill
- hexagonal-architectureSkill
- impeccableSkill
- internationalization-localizationSkill
- javascript-typescript-engineeringSkill
- justfilesSkill
- mcp-server-engineeringSkill
- mysql-mariadb-sql-engineeringSkill
- observability-engineeringSkill
- onion-architectureSkill
- parallelism-engineeringSkill
- performance-reviewSkill
- playwright-e2eSkill
- postgresql-sql-engineeringSkill
- prompt-engineering-reviewSkill
- python-antipatternsSkill
- python-design-patternsSkill
- python-engineeringSkill
- random-data-identifiersSkill
- release-readinessSkill
- review-verification-protocolSkill
- root-cause-analysisSkill
- ruby-engineeringSkill
- rust-antipatternsSkill
- rust-async-webSkill
- rust-code-reviewSkill
- rust-design-patternsSkill
- rust-desktop-guiSkill
- rust-engineeringSkill
- rust-persistence-sqlSkill
- rust-testing-qualitySkill
- script-engineeringSkill
- security-review-evidenceSkill
- security-reviewSkill
- semantic-versioningSkill
- sql-engineeringSkill
- sqlite-sql-engineeringSkill
- suggest-lucide-iconsSkill
- The first 60 shown.
The file
Show its rules and text
We split this skill into the rules it gives an agent
23 rules. About 0 are common, 4 are distinctive, and 19 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.
19
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 8
Use this skill for Svelte component design, Svelte 5 runes/reactivity, and SvelteKit application structure, routing, data loading, and form …
- Very specific: line 29
Use standalone Svelte (via Vite's svelte template, a component library, or embedding Svelte components into an existing non-Svelte page) …
- Distinctive: line 45
Use SvelteKit when any of these apply:
- Distinctive: line 61
If a project starts as standalone Svelte and later needs routing, SSR, or a backend-for-frontend layer, migrating to SvelteKit is …
- Very specific: line 99
Use the context API (setContext/getContext) to pass state down a component tree without prop-drilling through intermediate components that …
- Very specific: line 114
Use $derived — it is pull-based and avoids ordering bugs and extra renders.
- Very specific: line 128
Keep components focused on presentation and local interaction.
- Very specific: line 132
Prefer composition (slots/snippets, {#snippet}/{@render} in Svelte 5, or child components) over large components with many boolean props …
- Very specific: line 139
Keep two-way binding (bind:) to genuine form-control-like components.
- Very specific: line 162
Put shared, non-route code under src/lib (aliased as $lib) — components, utilities, stores/runes modules, server-only helpers.
- Very specific: line 170
Keep hooks.server.js/hooks.client.js for cross-cutting concerns: authentication population (event.locals), request logging, error …
- Very specific: line 174
Use app.d.ts to type App.Locals, App.PageData, App.Error, and App.Platform so event.locals and load return values are typed end-to-end …
- Very specific: line 177
Keep a clear module boundary between UI components ($lib/components), domain/service logic ($lib/server/* or $lib/domain/*), and route glue …
- Very specific: line 203
Use +page.server.js/+server.js for anything that must stay server-only.
- Very specific: line 231
Prefer load functions and streaming (export const load = async () => ({ streamed: { slow: slowPromise() } })) over client-side spinners for …
- Very specific: line 234
Use data-sveltekit-preload-data (on by default for hover) deliberately.
- Very specific: line 237
Prefer prerendering (export const prerender = true) for content that is the same for every visitor and does not depend on cookies/session — …
- Very specific: line 240
Avoid importing large libraries into universal code that also ships to the client.
- Very specific: line 243
Use $derived instead of recomputing expensive values in the template or in an $effect on every dependency change.
- Very specific: line 251
Use error(status, message) from @sveltejs/kit in load functions and actions for expected failures (404, 403, validation) so SvelteKit …
- Very specific: line 274
Test load functions and form actions directly as functions (they are plain exported functions) with a constructed event-like object, rather …
- Very specific: line 277
Use playwright-e2e for checked-in end-to-end coverage of navigation, form submission with progressive enhancement, authentication flows, …
- Distinctive: line 331
No per-request mutable state lives in module scope on the server.
≈ “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
Svelte and SvelteKit Engineering
Use this skill for Svelte component design, Svelte 5 runes/reactivity, and
SvelteKit application structure, routing, data loading, and form handling.
Inspect the repository before assuming a version: check package.json for
svelte/@sveltejs/kit major versions, svelte.config.js for the adapter, and
whether components use runes ($state, $derived, $effect, $props) or
legacy Svelte 4 syntax (export let, $:, writable stores as the default
reactivity model). Do not silently rewrite Svelte 4 idioms to runes, or vice
versa, unless the task is an explicit migration.
Load javascript-typescript-engineering
for package manager workflow, TypeScript configuration, bundler/Vite mechanics,
and generic JS/TS lint/build/test commands. Load
css-scss-styling for <style> block
architecture, Tailwind, CSS modules, and design tokens. This skill owns
Svelte-specific and SvelteKit-specific decisions only.
Svelte (Standalone) vs. SvelteKit
Choose deliberately; do not default to SvelteKit for every UI, and do not reach for standalone Svelte once routing or server behavior is needed.
Use standalone Svelte (via Vite's svelte template, a component library, or
embedding Svelte components into an existing non-Svelte page) when:
- The project is a single component, a widget embedded in another site or CMS, a design-system/component-library package, or a browser extension UI.
- There is no need for file-based routing, multiple pages, or navigation state owned by the framework.
- Rendering is client-only and SEO, first-paint content, or crawlability do not
matter — e.g., an internal dashboard behind auth, an admin widget, or a
<canvas>/data-viz component. - The app has no server-side concerns of its own: no need to keep secrets off the client, call a database directly, or render personalized HTML before JavaScript runs.
- Deployment target is a static asset host or the component ships inside another application's bundle (npm package, Web Component wrapper).
Use SvelteKit when any of these apply:
- The app needs more than one route, nested layouts, or URL-driven navigation.
- Pages need SSR or prerendering for SEO, social-preview metadata, or fast perceived load on slow connections/devices.
- The app must keep secrets (API keys, database credentials) off the client —
+page.server.js/+server.jsrun only on the server. - The app needs form handling with progressive enhancement, cookie-based sessions, or server-validated mutations (form actions).
- Deployment targets a Node server, edge runtime (Cloudflare Workers, Vercel Edge, Deno Deploy), or a serverless platform — SvelteKit adapters exist for these; plain Svelte does not manage server output.
- The app benefits from SvelteKit's file-based conventions (
+page.svelte,+layout.svelte,+server.js) to avoid hand-rolling a router, data-loading convention, or error-boundary pattern.
If a project starts as standalone Svelte and later needs routing, SSR, or a backend-for-frontend layer, migrating to SvelteKit is straightforward because SvelteKit is built on the same component model — prefer that migration over hand-building routing/SSR on top of plain Svelte.
Reactivity: Runes vs. Legacy Reactivity
Svelte 5 introduced runes as the default reactivity primitive. Match the repository's actual syntax; a mixed codebase mid-migration is normal but new code should follow the direction the repo has already chosen.
$statereplaces implicit top-level reactiveletbindings. Use it for any local mutable value a component template reads.$stateis deeply reactive for plain objects/arrays; mutating a property (obj.x = 1,arr.push(...)) triggers updates without needing to reassign.$derived(and$derived.by(() => ...)for multi-statement logic) replaces$:reactive declarations for computed values. Prefer$derivedover$effectwhenever a value is computed from other state —$effectis for side effects, not for producing values other code reads.$effectreplaces$:used for side effects (DOM APIs, subscriptions, logging, syncing tolocalStorage). Keep effects narrow and clean up subscriptions/timers/listeners by returning a teardown function. Avoid$effectfor state derivation — an effect that only sets another$statefrom its dependencies is a smell; use$derivedinstead.$propsreplacesexport letfor declaring component inputs, including defaults (let { count = 0 } = $props()) and rest props (let { class: className, ...rest } = $props()).$bindablemarks a prop that a parent may bind to withbind:; only mark props bindable when two-way binding is a deliberate part of the component's contract, not by default.- Stores (
writable,readable,derivedfromsvelte/store) are still useful for state that must be shared across component instances without prop-drilling, state that outlives a single component tree (app-wide settings, auth session), or state consumed outside components (e.g., in a.tsmodule). Runes replace stores for component-local reactive state; they do not replace the store contract for cross-cutting shared state, though$statein a plain.svelte.js/.svelte.tsmodule is now a common runes-based alternative to a store for shared state. - Use the context API (
setContext/getContext) to pass state down a component tree without prop-drilling through intermediate components that don't use it themselves — typically paired with a$stateobject so descendants get reactive updates. Context is not a global store: it is scoped to the component tree rooted wheresetContextwas called, which makes it safe for per-request/per-instance state (important in SSR, where a module-level singleton would leak state between requests).
Reactivity Anti-Patterns
- Module-level mutable
$state/store used to hold per-request or per-user data in a SvelteKit app. On the server, module scope is shared across concurrent requests — this leaks one user's data into another's response. Useloadreturn values,event.locals, or context populated per-request instead. - Using
$effectto derive a value that other code reads ($effect(() => count2 = count * 2)). Use$derived— it is pull-based and avoids ordering bugs and extra renders. - Deep-cloning or reassigning entire objects/arrays to force reactivity. With
$state, mutation is already tracked; reassignment gymnastics left over from Svelte 4's array-reassignment workaround are unnecessary and hurt readability. - Subscribing to a store manually with
.subscribe()inside a component instead of using the$storeauto-subscription syntax, causing manual unsubscribe bugs and memory leaks in components without a matching cleanup. - Putting business logic inside
$effectblocks that reach into the DOM directly when a declarative binding (bind:value,class:,style:) would do the same thing more predictably.
Component Design
- Keep components focused on presentation and local interaction; push data
fetching, validation, and cross-cutting business rules to
loadfunctions, form actions, or plain.tsmodules that components import. A component that both fetches data and renders it is harder to test and reuse. - Prefer composition (slots/snippets,
{#snippet}/{@render}in Svelte 5, or child components) over large components with many boolean props that toggle internal branches. Avariant/boolean-prop explosion is a sign the component should split or use composition instead. - Type props explicitly in TypeScript projects (
let { items }: { items: Item[] } = $props();) rather than inferring from usage; this keeps the component's contract visible at a glance and catches mismatches at the call site. - Keep two-way binding (
bind:) to genuine form-control-like components. Avoid exposingbind:on every prop by default — most parent/child communication should flow one-directionally down via props and up via callback props or events, reserving$bindablefor controls that behave like native form elements. - Name event-handling props consistently (
onclick,onsubmit, or a domain name likeonSelect) since Svelte 5 uses plain props for event handlers rather thancreateEventDispatcherin new code; reservecreateEventDispatcherfor maintaining existing Svelte 4 component contracts. - Co-locate a component's styles in its own
<style>block; Svelte scopes styles per component automatically, so avoid hand-rolled class-name namespacing to prevent collisions. Route non-trivial styling architecture decisions tocss-scss-styling.
Project Structure and File Conventions
- Respect SvelteKit's routing conventions in
src/routes:+page.sveltefor a page,+layout.sveltefor shared layout,+page.server.js/.tsand+layout.server.jsfor server-only data and actions,+server.jsfor standalone API endpoints, and+error.sveltefor route-scoped error UI. Route groups ((group)) organize routes without affecting the URL; matcher files (src/params/*.js) validate dynamic segment shape. - Put shared, non-route code under
src/lib(aliased as$lib) — components, utilities, stores/runes modules, server-only helpers. Use$lib/server(or an equivalent convention) for modules that must never be imported from client-rendered code, and treat any import of a server-only module from a+page.svelteas a bug: SvelteKit only enforces this boundary for code that actually reaches+page.server.js/+server.js/hooks.server.js— a client-imported module has no such protection, so keep secrets and privileged logic out of anything reachable from the client bundle. - Keep
hooks.server.js/hooks.client.jsfor cross-cutting concerns: authentication population (event.locals), request logging, error normalization. Avoid stuffing route-specific logic into hooks — that belongs in the route's ownload/action/server endpoint. - Use
app.d.tsto typeApp.Locals,App.PageData,App.Error, andApp.Platformsoevent.localsandloadreturn values are typed end-to-end instead ofany. - Keep a clear module boundary between UI components (
$lib/components), domain/service logic ($lib/server/*or$lib/domain/*), and route glue (+page.server.ts,+server.ts). Route files should stay thin — parse input, call a service function, shape the response — mirroring the thin-handler guidance inhexagonal-architecturewhen the backend logic is substantial enough to warrant explicit ports/adapters.
Design Patterns
Load the Svelte/SvelteKit patterns reference for
worked guidance on layout composition, load function design (universal vs.
server, streaming/parallel loading, invalidation), form actions and
progressive enhancement, and other patterns that appear repeatedly in
production SvelteKit apps.
Anti-Patterns
Load the Svelte/SvelteKit anti-patterns reference for a fuller catalogue. Highest-impact items:
- Fetching data in
onMount/$effectinside a page component instead of aloadfunction — this delays rendering, breaks SSR, and duplicates loading/error-state handling that SvelteKit already provides. - Calling a database, ORM, or secret-bearing API directly from a
.sveltecomponent or a universalload(+page.js) that also runs in the browser. Use+page.server.js/+server.jsfor anything that must stay server-only. - Storing all application state in one global store, turning it into an
untyped, unscoped god-object. Scope state to the route or component tree that
owns it; use context or route-level
loaddata instead. - Reimplementing form submission with
fetchand manualpreventDefaultwhen a form action plususe:enhancewould give the same UX with progressive enhancement and less code. - Ignoring
+error.svelteand letting every failure fall through to a generic crash page, instead of throwingerror()/redirect()fromloador actions with actionable status codes and messages.
Backend Integration
Load the backend integration reference when a SvelteKit frontend talks to a separate backend service (Rust/Axum, PHP, Python/FastAPI or Django, or another API) rather than owning all server logic itself. It covers API communication patterns, authentication handoff (cookies vs. bearer tokens, BFF vs. direct-to-API), and deployment topology choices.
Route the backend's own implementation to its owning skill:
rust-async-web for Axum and
python-engineering for FastAPI/Django. Use
api-design when the contract itself (resource
shape, error envelope, versioning) is still being decided. This skill owns only
how the SvelteKit side consumes and is deployed alongside that backend.
Performance
- Prefer
loadfunctions and streaming (export const load = async () => ({ streamed: { slow: slowPromise() } })) over client-side spinners for expensive data — SvelteKit can render the shell immediately and stream slow data in. - Use
data-sveltekit-preload-data(on by default forhover) deliberately; disable preloading for expensive or side-effecting links rather than leaving it default everywhere. - Prefer prerendering (
export const prerender = true) for content that is the same for every visitor and does not depend on cookies/session — it removes server round-trips entirely for that route. - Avoid importing large libraries into universal code that also ships to the
client; keep heavy parsing/formatting/crypto libraries in
+page.server.tswhen the result, not the library, is what the client needs. - Use
$derivedinstead of recomputing expensive values in the template or in an$effecton every dependency change;$derivedvalues are cached until a dependency actually changes. - Route deeper profiling, bundle-budget, or Core Web Vitals work to
performance-review.
Error Handling
- Use
error(status, message)from@sveltejs/kitinloadfunctions and actions for expected failures (404, 403, validation) so SvelteKit renders the nearest+error.sveltewith the right status code. - Return
fail(status, data)from form actions for validation errors so the form re-renders with the submitted values and field errors, instead of throwing and losing form state. - Implement
handleErrorinhooks.server.js/hooks.client.jsto log unexpected exceptions with a correlation id and return a safe, user-facing message — never leak stack traces or internal error details to the client in production. Route structured logging/correlation-id design toobservability-engineering. - Distinguish expected domain errors (validation, not-found, unauthorized) from
unexpected exceptions (bugs, network failures) — only the former should
produce a specific status code and message; let the latter hit
handleError.
Testing
- Unit-test pure logic (utilities, derived-state functions, form-validation schemas) with the repository's configured runner (commonly Vitest) without mounting components.
- Component-test with
@testing-library/svelte(or the repo's established tool) for rendering behavior, prop/event contracts, and accessibility roles — test what the user sees and does, not internal component state. - Test
loadfunctions and form actions directly as functions (they are plain exported functions) with a constructedevent-like object, rather than only through full page renders. - Use
playwright-e2efor checked-in end-to-end coverage of navigation, form submission with progressive enhancement, authentication flows, and hydration-sensitive behavior that only a real browser can verify. Loadtesting-strategyfor deciding the overall unit/component/E2E balance.
Accessibility
Svelte's compiler emits accessibility warnings (missing alt, invalid ARIA
roles, non-interactive elements with click handlers) — treat these as build
warnings to fix, not noise to suppress with <!-- svelte-ignore --> unless the
suppression is justified and commented. Load
ux-accessibility-review for a full
accessibility audit of interactive components, forms, and focus management
(especially around client-side navigation, where SvelteKit does not
automatically move focus or announce route changes the way a full page load
would).
Security Review Prompts
Load security-review when SvelteKit work
touches authentication, session cookies, CSRF, form actions that mutate state,
redirects, file uploads, +server.js endpoints exposed to the internet, or
data rendered with {@html ...} (a raw HTML injection point). Use
threat-modeling before or during new
hooks.server.js auth logic, new +server.js endpoints, or a new
backend-for-frontend boundary. Use
dependency-supply-chain-review
for svelte/@sveltejs/kit/adapter/plugin version bumps and new dependencies.
Deployment and Adapters
- Match the SvelteKit adapter to the actual deployment target:
@sveltejs/adapter-nodefor a long-running Node server,@sveltejs/adapter-staticfor a fully prerendered static site,@sveltejs/adapter-vercel/adapter-netlify/adapter-cloudflarefor those platforms, and community adapters for other targets. Do not assume Vercel by default — checksvelte.config.js. - Static/prerendered output has no server runtime:
+page.server.js,+server.js, and form actions requiring a live server will not work underadapter-staticunless the route is explicitly excluded from prerendering and the platform still runs a server. - Route Dockerfile/Compose packaging to
container-engineeringand hosted CI/CD pipeline configuration toci-release-engineering; keep adapter selection and environment-variable/platform-binding mechanics here.
Review Checklist
- Standalone Svelte vs. SvelteKit was a deliberate choice based on routing, SSR, secret-handling, and deployment needs — not a default.
- Reactivity uses
$state/$derived/$effect/$propscorrectly in Svelte 5 code, with no$effectused purely to derive a value. - No per-request mutable state lives in module scope on the server.
- Data fetching and secret-bearing calls happen in
load/+server.js/actions, never directly in.sveltecomponents or client-reachable code. - Route files stay thin; domain/service logic lives in
$lib. - Forms use actions plus
use:enhancewhere progressive enhancement matters; validation errors return viafail, not thrown exceptions. - Errors distinguish expected (
error()/fail()) from unexpected (handleError) cases, and no internal details leak to the client. - The adapter matches the real deployment target, and prerendered routes don't depend on per-request server behavior.
- Accessibility warnings from the Svelte compiler are addressed, not suppressed, and route-change focus/announcement is considered.
- Tests exist at the right layer: unit for logic, component tests for rendering/interaction, Playwright E2E for hydration- and navigation-sensitive flows.
Zod SvelteKit Routing
For selected Zod schemas, load zod-engineering. Parse in server loads/actions/endpoints where appropriate, keep server-only code out of client bundles, validate runtime responses, and map expected failures to supported fail/error shapes.
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.

