Using Svelte Reactive Statements ($:) to Keep Derived Values in Sync
Learn how Svelte's reactive statements automatically update derived values when dependencies change, with a simple counter example, a derived array example, limits, and common pitfalls.
12 Jun 2026, 11:49 UTC

Svelte’s reactive statements, written with the $: label, let you declare a value that automatically updates whenever any of the variables it references change. This eliminates the need for manual subscriptions or imperative update logic in many UI components.
How reactive statements work
When the Svelte compiler sees a $: block, it treats the block as a piece of code that must re‑run after every micro‑task in which any of its referenced variables have been modified. The block runs synchronously after the current call stack clears, before the browser paints the next frame. Because the re‑run is tied to the dependency set, the derived value stays in sync with the source without extra bookkeeping.
Example component – simple counter
<script>
let count = 0;
$: doubled = count * 2;
</script>
<button on:click={() => count += 1}>Click me: {count}</button>
<p>Doubled: {doubled}</p>
In this snippet, count is a mutable variable. The reactive statement $: doubled = count * 2; creates a derived variable doubled. Each time the button increments count, Svelte schedules the reactive block to run after the click handler finishes. The new value of doubled is then reflected in the markup without any additional code.
Example component – derived array
<script>
let items = [
{ name: 'Widget', price: 50 },
{ name: 'Gadget', price: 150 },
{ name: 'Doohickey', price: 80 }
];
$: expensive = items.filter(i => i.price > 100);
</script>
<ul>
{#each expensive as item}
{item.name} – ${item.price}
{/each}
</ul>
Here the reactive statement derives a new array expensive containing only items whose price exceeds 100. When items changes (e.g., an element is added, removed, or its price updated), the filter expression re‑executes and the list updates automatically.
Limits and common mistakes
- Single micro‑task per change. If a variable changes multiple times within the same tick (for example, inside a tight loop), the reactive block executes only once after the loop finishes. This can hide intermediate states.
- No asynchronous code. The body of a
$:block cannot containawaitor return a promise; doing so produces a compile‑time error. For async work, useawaitinside a function called from the block or rely on stores and lifecycle events. - Cannot be nested in loops or conditionals. Placing a reactive statement inside a
{#each}block, an{#if}branch, or any other markup‑level control flow causes a syntax error. Move the logic to the component’s script section. - Missing dependencies. If you reference a variable that is not declared in the component’s scope (for instance, a typo or a variable imported incorrectly), the reactive block will not re‑run when that variable changes, leading to stale UI.
- Expensive work. Because the block runs on every change, heavy calculations or direct DOM manipulation inside it can degrade performance. Offload costly operations to a
setTimeout,requestAnimationFrame, or a dedicated store.
Verification approach
To confirm that a reactive statement behaves as described, open the official Svelte REPL () and paste the example component above. Click the button and observe the doubled value update instantly. For a more explicit check, add console.log('reactive ran') inside the $: block; each click should produce a new log entry in the browser’s console, proving the block re‑executes on every change. The same procedure works for the array‑filtering example: modify the items array (e.g., push a new object) and verify that the expensive list updates accordingly.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.