Svelte 5 Runes
The five core runes ($state, $derived, $effect, $props, $bindable) plus $inspect and $host — Svelte 5's unified reactivity system.
Runes are Svelte 5’s unified reactivity primitives — compiler-level signals that replace the Svelte 4 let / export let / $: / store ecosystem. They work in .svelte files and .svelte.js / .svelte.ts modules.
$state
$state is the foundation of Svelte 5 reactivity. It transforms ordinary variables into reactive state — when the value changes, the UI updates automatically.
<script>
let count = $state(0)
</script>
<button onclick={() => count++}>Clicks: {count}</button> $state deeply proxies arrays and objects, meaning nested property access is reactive. Use $state.raw() to opt out of deep reactivity for performance with large immutable data. Use $state.snapshot() to get a non-reactive copy of reactive state.
$derived
$derived creates computed values that update automatically when their dependencies change. It is the rune replacement for $: derived declarations.
<script>
let count = $state(0)
let doubled = $derived(count * 2)
</script> Use $derived.by() for multi-statement computations. Derived values are read-only and synchronously computed — no stale data, no manual subscription management.
$effect
$effect runs side effects in response to state changes. It is the rune replacement for $: side-effect statements and lifecycle-based patterns.
<script>
let count = $state(0)
$effect(() => {
console.log('Count changed to', count)
})
</script> $effect is not componentDidMount — it runs whenever its tracked dependencies change, not just once. Use $effect.root() for manual lifecycle management and $effect.pre() to run effects before DOM updates.
$props
$props declares component inputs as a destructured object. It replaces export let from Svelte 4.
<script>
let { name, age = 18, ...rest } = $props()
</script> All props are reactive by default. Default values are used when no prop is passed. Rest properties capture any additional props passed to the component.
$bindable
$bindable marks a prop as eligible for two-way binding with bind:. By default, props are one-way (parent to child). Adding $bindable() to a prop declaration allows bind:propName on the parent side.
<script>
let { value = $bindable() } = $props()
</script> $inspect
$inspect logs reactive values for debugging, firing whenever the tracked value changes. It is a development-only tool that self-removes in production builds.
<script>
let count = $state(0)
$inspect(count)
</script> $host
$host is used in the context of Svelte 5 custom elements. It returns the host element reference, enabling access to the custom element’s DOM API.
Fine-Grained Reactivity
Svelte 5’s runes provide fine-grained reactivity at the variable level, not the component level. This means:
- Only the specific DOM nodes that depend on a reactive value update
- No virtual DOM, no diffing — direct DOM updates
- Reactive values work seamlessly across
.svelte.js/.svelte.tsmodule boundaries - Class instances with
$statefields are fully reactive
See Also
- Svelte 5 Template Syntax
- Svelte Context API — for sharing reactive state across the component tree
- CALM Systems Philosophy — principles for using runes in maintainable apps
