Svelte 5 introduces a new reactivity system built on runes, gradually replacing the old reactive variables. Runes like $state, $derived and $effect give you more explicit control over how data changes over time.

$state: the source of truth

The $state rune replaces the reactive let declarations of Svelte 4. It works for primitives as well as objects and arrays, with deep reactivity by default:

<script>
    let count = $state(0);

    function increment() {
        count += 1;
    }
</script>

<button onclick={increment}>
    Clicks: {count}
</button>

$derived: computed values

$derived replaces $: statements for derived values. The computation is memoized and only re-runs when its dependencies change:

<script>
    let count = $state(0);
    let double = $derived(count * 2);
    let isEven = $derived(count % 2 === 0);
</script>

<p>{count} doubled is {double} ({isEven ? 'even' : 'odd'})</p>

$effect: side effects

$effect runs after rendering, every time one of its dependencies changes, and can return a cleanup function:

<script>
    let count = $state(0);

    $effect(() => {
        document.title = `Counter: ${count}`;

        return () => {
            console.log('cleanup before the next effect');
        };
    });
</script>

Quick comparison with Svelte 4

Svelte 4 Svelte 5 Role
let x = 0 let x = $state(0) Local state
$: y = x * 2 let y = $derived(x * 2) Derived value
$: { ... } $effect(() => { ... }) Side effect
export let prop let { prop } = $props() Component props

Runes are not regular imports: they are keywords compiled by Svelte, recognizable by their $ prefix.

Svelte documentation

This approach brings Svelte closer to other modern frameworks while keeping its minimalist syntax. Developers used to the previous version will need to adjust some habits, but the migration stays largely gradual thanks to the backward compatibility the team provides.

In upcoming articles, we'll explore concrete uses of runes in real projects, notably for state shared between components, for example through a .svelte.js file:

// counter.svelte.js
export function createCounter(initial = 0) {
    let count = $state(initial);

    return {
        get value() {
            return count;
        },
        increment() {
            count += 1;
        },
    };
}

To go further, the official documentation remains the best resource: https://svelte.dev/docs/svelte/what-are-runes