Derived values: $derived
Often one value depends entirely on another: the number of remaining tasks on the list of tasks, the total price on the quantity and the price. Such values are not stored separately but computed with the $derived rune. Svelte recalculates them when the data they come from changes.
The $derived rune
<!-- src/routes/+page.svelte -->
<script>
let todos = $state([
{ id: 1, text: 'Buy bread', done: true },
{ id: 2, text: 'Call Oleg', done: false }
]);
let remaining = $derived(todos.filter((todo) => !todo.done).length);
</script>
<p>Tasks left: {remaining}</p>
<button onclick={() => (todos[1].done = true)}>Finish the second</button>At first the page shows "Tasks left: 1", after the click — "Tasks left: 0". You do not recalculate remaining by hand: Svelte sees that the expression reads todos and updates the result whenever the list changes.
Chained calculations
A derived value can depend on another derived value:
<script>
let todos = $state([
{ id: 1, text: 'Buy bread', done: true },
{ id: 2, text: 'Call Oleg', done: false }
]);
let doneCount = $derived(todos.filter((todo) => todo.done).length);
let percent = $derived(Math.round((doneCount / todos.length) * 100));
</script>
<p>Done: {percent}%</p>The page shows "Done: 50%". If you mark the second task, doneCount is recalculated first, then percent, and the text becomes "Done: 100%".
Complex calculations: $derived.by
$derived takes a single expression. If the calculation needs several lines, use $derived.by with a function:
<script>
let todos = $state([
{ id: 1, text: 'Buy bread', done: true },
{ id: 2, text: 'Call Oleg', done: false }
]);
let filter = $state('all');
let visible = $derived.by(() => {
if (filter === 'active') return todos.filter((todo) => !todo.done);
if (filter === 'done') return todos.filter((todo) => todo.done);
return todos;
});
</script>
<button onclick={() => (filter = 'active')}>Active</button>
<p>Tasks shown: {visible.length}</p>At first two tasks are shown, after clicking "Active" — one. The value depends on both todos and filter: a change in either one triggers a recalculation.
$derived or a function
You could write a getRemaining() function and call it in the markup. But a function runs again in every place where it is called, while $derived is computed once, remembers the result and recomputes it only when its dependencies have changed. It is also read like a regular variable — both in the markup and in the script.
Common mistake
Storing a derived value in $state and updating it by hand:
<script>
let todos = $state([]);
let remaining = $state(0);
function addTodo(text) {
todos.push({ id: Date.now(), text, done: false });
remaining = remaining + 1;
}
</script>Forget to update remaining in one place — for example, when a task is deleted — and the number on the page no longer matches the list. Anything computed from other state should be declared with $derived.