svelte-core-bestpractices
Skill1 starsChanged 3 months agoMITView on GitHub
Guidance on writing fast, robust, modern Svelte code. Load this skill whenever in a Svelte project and asked to write/edit or analyze a Svelte component or module. Covers reactivity, event handling, styling, integration with libraries and more.
8 other projects use a version of this, 6 of them edited.
Adopted by
Most recently taken up by
- oekazuma/svelte-meta-tagsedited, first seen Oct 9, 2026
- wesm/middlemanedited, first seen Oct 9, 2026
- pinkfuwa/llumenedited, first seen Oct 8, 2026
- chattocorp/chattoedited, first seen Oct 8, 2026
- rilldata/rilledited, first seen Oct 8, 2026
- jacksteamdev/cloudflare-workers-templateedited, first seen Aug 25, 2026
Other versions8 projects use a version of this.
Word for word · 1
- Fractal-Tess/oh-my-pi★ 1100% same
Edited · 6
- rilldata/rill★ 3k99% same
- chattocorp/chatto★ 2.9k93% same
- oekazuma/svelte-meta-tags★ 685100% same
- wesm/middleman★ 198100% same
- pinkfuwa/llumen★ 10193% same
- jacksteamdev/cloudflare-workers-template★ 0100% same
Wrote their own version · 1
- spences10/skills★ 15same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository22 other files it gives its agents.
- skills/vercel-composition-patterns/AGENTS.mdAGENTS.md
- skills/vercel-react-best-practices/AGENTS.mdAGENTS.md
- agent-browserSkill
- design-taste-frontendSkill
- fal-image-genSkill
- find-skillsSkill
- ft-netbird-shareSkill
- ft-readme-styleSkill
- ft-visual-styleSkill
- gitadelSkill
- impeccableSkill
- react-bits-proSkill
- react-doctorSkill
- researchSkill
- rust-best-practicesSkill
- scorchSkill
- shell-secretsSkill
- supermemory-auditSkill
- svelte-code-writerSkill
- unslopSkill
- vercel-composition-patternsSkill
- vercel-react-best-practicesSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
26 rules. 4 are common, 1 is distinctive, and 21 are very specific to this project.
4
Common
Most of the 7 edited versions we read keep these.
1
Distinctive
This author's own choices. Worth a look.
21
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 8
Only use the $state rune for variables that should be _reactive_ — in other words, variables that cause an $effect, $derived or template …
- Very specific: line 32
If the derived expression is an object or array, it will be returned as-is — it is _not_ made deeply reactive.
- Very specific: line 38
If you need to sync state to an external library such as D3, it is often neater to use {@attach ...}
- Common: line 39
If you need to run some code in response to user interaction, put the code directly in an event handler or use a function binding as …
- Very specific: line 40
If you need to log values for debugging purposes, use $inspect
- Very specific: line 41
If you need to observe something external to Svelte, use createSubscriber
- Very specific: line 43
Never wrap the contents of an effect in if (browser) {...} or similar — effects do not run on the server.
- Very specific: line 47
Treat props as though they will change.
- Very specific: line 78
If you need to attach listeners to window or document you can use <svelte:window> and <svelte:document>:
- Very specific: line 85
Avoid using onMount or $effect for this.
- Common: line 103
Prefer to use keyed each blocks — this improves performance by allowing Svelte to surgically insert or remove items rather than updating …
- Very specific: line 107
Avoid destructuring if you need to mutate the item (with something like bind:value={item.count}, for example).
- Very specific: line 111
If you have a JS variable that you want to use inside CSS you can set a CSS custom property with the style: directive.
- Very specific: line 137
If this is impossible (for example, the child component comes from a library) you can use :global to override styles:
- Common: line 155
Consider using context instead of declaring state in a shared module.
- Very specific: line 157
Use createContext rather than setContext and getContext, as it provides type safety.
- Distinctive: line 161
If using version 5.36 or higher, you can use await expressions and hydratable to use promises directly inside components.
- Common: line 165
Always use runes mode for new code, and avoid features that have more modern replacements:
- Very specific: line 167
use $state instead of implicit reactivity (e.g.
- Very specific: line 168
use $derived and $effect instead of $: assignments and statements (but only use effects when there is no better solution)
- Very specific: line 169
use $props instead of export let, $$props and $$restProps
- Very specific: line 170
use onclick={...} instead of on:click={...}
- Very specific: line 171
use {#snippet ...} and {@render ...} instead of <slot> and $$slots and <svelte:fragment>
- Very specific: line 173
use import Self from './ThisComponent.svelte' and <Self> instead of <svelte:self>
- Very specific: line 174
use classes with $state fields to share reactivity between components, instead of using stores
- Very specific: line 176
use clsx-style arrays and objects in class attributes, instead of the class: directive
“Common” is measured: kept by at least 6 in 10 of the 7 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
$state
Only use the $state rune for variables that should be reactive — in other words, variables that cause an $effect, $derived or template expression to update. Everything else can be a normal variable.
Objects and arrays ($state({...}) or $state([...])) are made deeply reactive, meaning mutation will trigger updates. This has a trade-off: in exchange for fine-grained reactivity, the objects must be proxied, which has performance overhead. In cases where you're dealing with large objects that are only ever reassigned (rather than mutated), use $state.raw instead. This is often the case with API responses, for example.
$derived
To compute something from state, use $derived rather than $effect:
// do this
let square = $derived(num * num);
// don't do this
let square;
$effect(() => {
square = num * num;
});[!NOTE]
$derivedis given an expression, not a function. If you need to use a function (because the expression is complex, for example) use$derived.by.
Deriveds are writable — you can assign to them, just like $state, except that they will re-evaluate when their expression changes.
If the derived expression is an object or array, it will be returned as-is — it is not made deeply reactive. You can, however, use $state inside $derived.by in the rare cases that you need this.
$effect
Effects are an escape hatch and should mostly be avoided. In particular, avoid updating state inside effects.
- If you need to sync state to an external library such as D3, it is often neater to use
{@attach ...} - If you need to run some code in response to user interaction, put the code directly in an event handler or use a function binding as appropriate
- If you need to log values for debugging purposes, use
$inspect - If you need to observe something external to Svelte, use
createSubscriber
Never wrap the contents of an effect in if (browser) {...} or similar — effects do not run on the server.
$props
Treat props as though they will change. For example, values that depend on props should usually use $derived:
// @errors: 2451
let { type } = $props();
// do this
let color = $derived(type === 'danger' ? 'red' : 'green');
// don't do this — `color` will not update if `type` changes
let color = type === 'danger' ? 'red' : 'green';$inspect.trace
$inspect.trace is a debugging tool for reactivity. If something is not updating properly or running more than it should you can add $inspect.trace(label) as the first line of an $effect or $derived.by (or any function they call) to trace their dependencies and discover which one triggered an update.
Events
Any element attribute starting with on is treated as an event listener:
<button onclick={() => {...}}>click me</button>
<!-- attribute shorthand also works -->
<button {onclick}>...</button>
<!-- so do spread attributes -->
<button {...props}>...</button>If you need to attach listeners to window or document you can use <svelte:window> and <svelte:document>:
<svelte:window onkeydown={...} />
<svelte:document onvisibilitychange={...} />Avoid using onMount or $effect for this.
Snippets
Snippets are a way to define reusable chunks of markup that can be instantiated with the {@render ...} tag, or passed to components as props. They must be declared within the template.
{#snippet greeting(name)}
<p>hello {name}!</p>
{/snippet}
{@render greeting('world')}[!NOTE] Snippets declared at the top level of a component (i.e. not inside elements or blocks) can be referenced inside
<script>. A snippet that doesn't reference component state is also available in a<script module>, in which case it can be exported for use by other components.
Each blocks
Prefer to use keyed each blocks — this improves performance by allowing Svelte to surgically insert or remove items rather than updating the DOM belonging to existing items.
[!NOTE] The key must uniquely identify the object. Do not use the index as a key.
Avoid destructuring if you need to mutate the item (with something like bind:value={item.count}, for example).
Using JavaScript variables in CSS
If you have a JS variable that you want to use inside CSS you can set a CSS custom property with the style: directive.
<div style:--columns={columns}>...</div>You can then reference var(--columns) inside the component's <style>.
Styling child components
The CSS in a component's <style> is scoped to that component. If a parent component needs to control the child's styles, the preferred way is to use CSS custom properties:
<!-- Parent.svelte -->
<Child --color="red" />
<!-- Child.svelte -->
<h1>Hello</h1>
<style>
h1 {
color: var(--color);
}
</style>If this is impossible (for example, the child component comes from a library) you can use :global to override styles:
<div>
<Child />
</div>
<style>
div :global {
h1 {
color: red;
}
}
</style>Context
Consider using context instead of declaring state in a shared module. This will scope the state to the part of the app that needs it, and eliminate the possibility of it leaking between users when server-side rendering.
Use createContext rather than setContext and getContext, as it provides type safety.
Async Svelte
If using version 5.36 or higher, you can use await expressions and hydratable to use promises directly inside components. Note that these require the experimental.async option to be enabled in svelte.config.js as they are not yet considered fully stable.
Avoid legacy features
Always use runes mode for new code, and avoid features that have more modern replacements:
- use
$stateinstead of implicit reactivity (e.g.let count = 0; count += 1) - use
$derivedand$effectinstead of$:assignments and statements (but only use effects when there is no better solution) - use
$propsinstead ofexport let,$$propsand$$restProps - use
onclick={...}instead ofon:click={...} - use
{#snippet ...}and{@render ...}instead of<slot>and$$slotsand<svelte:fragment> - use
<DynamicComponent>instead of<svelte:component this={DynamicComponent}> - use
import Self from './ThisComponent.svelte'and<Self>instead of<svelte:self> - use classes with
$statefields to share reactivity between components, instead of using stores - use
{@attach ...}instead ofuse:action - use clsx-style arrays and objects in
classattributes, instead of theclass:directive
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.

