docs / Runtime

derived

A computed cell: recomputes only when something it reads changes, and reads like a plain value once unwrapped.

derived(fn) creates a cell whose value is computed from other cells. It is lazy and cached: nothing runs until the cell is read, and a read recomputes only when a dependency actually changed. Use it for values that are DERIVED — a total, a filtered list, a formatted string — never for values that are owned.

app/cart/page.vsk
									
										component Cart() {
  const &[items] = track([{ name: 'Vesk', price: 20 }])
  const total = derived(() => items.reduce((sum, i) => sum + i.price, 0))

  <p>Total: {get(total)}</p>
}
									
								

Read a derived cell with get(...). Printing the cell itself renders [object Object] — a derived cell is a cell, not a value, and the compiler does not unwrap it in markup the way it unwraps a track() binding.

Chaining

A derived can read another derived. Dependencies are tracked through the chain, so a change at the root updates everything downstream exactly once.

app/cart/page.vsk
									
										component Cart() {
  const &[items] = track([{ name: 'Vesk', price: 20 }])
  const total = derived(() => items.reduce((sum, i) => sum + i.price, 0))
  const withTax = derived(() => get(total) * 1.2)

  <p>Total: {get(total)} — with tax: {get(withTax)}</p>
}
									
								

With object and array members

app/list/page.vsk
									
										component TaskList() {
  const &[tasks] = track([
    { id: 1, title: 'Write docs', done: false },
    { id: 2, title: 'Ship it', done: false },
  ])

  const open = derived(() => tasks.filter((t) => !t.done))

  <ul>
    for (const task of get(open)) {
      <li>{task.title}</li>
    }
  </ul>
}
									
								

A derived must stay PURE — and the runtime enforces it rather than trusting you. Writing any tracked value from inside a derived throws immediately: 'Assignments or updates to tracked values are not allowed during computed evaluation'. Fetching inside a derived is the subtler mistake: it does not throw, it just runs again on the next dependency change, so you ship a duplicate request. Derived computes; effect acts.