Derived values with $derived

Svelte · Essentials · 9 min

Derived values keep the UI consistent without duplicating state or writing manual sync code.

When a value can be computed from other state, declare it with `$derived`:

let count = $state(0);
let doubled = $derived(count * 2);

Svelte tracks which state the expression reads and recalculates it when one of those changes. Derived values are lazy and cached: recomputed only when read after a dependency changed.

For logic that needs statements, use `$derived.by` with a function:

let stats = $derived.by(() => {
  let done = 0;
  for (const t of todos) if (t.done) done++;
  return { done, open: todos.length - done };
});

Rules and tips:

  • The expression must be free of side effects; Svelte disallows state changes inside a derived.
  • Dependencies are whatever is read synchronously inside it.
  • If the new value is identical (===) to the old one, dependents don't update.
  • Since Svelte 5.25 you can temporarily assign to a derived (for optimistic UI); it recalculates again when its dependencies change.

The common mistake from other frameworks is to use an effect that writes to another $state whenever something changes. If you can express a value as a function of other state, $derived is simpler, faster and never out of sync.

Example

<script>
  let todos = $state([
    { text: 'write', done: true },
    { text: 'test', done: false },
  ]);
  let filter = $state('all');

  let visible = $derived(
    filter === 'all' ? todos : todos.filter((t) => t.done === (filter === 'done'))
  );
  let stats = $derived.by(() => {
    const done = todos.filter((t) => t.done).length;
    return { done, open: todos.length - done };
  });
</script>

<select bind:value={filter}>
  <option>all</option><option>done</option><option>open</option>
</select>
<p>{stats.done} done, {stats.open} open</p>   <!-- 1 done, 1 open -->
<ul>{#each visible as t}<li>{t.text}</li>{/each}</ul>

Remember

  • $derived(expr) recomputes when state it reads changes
  • $derived.by(() => {...}) for multi-statement logic
  • Prefer derived over effects that copy state around

Watch out for

  • Using $effect to set one $state from another; that is exactly what $derived is for.

Check yourself

  1. `let total = $derived(price * qty)`. The user changes qty. When is total recalculated?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: svelte.dev/docs/svelte/$derived