Runes like $state, $derived, and $effect are not runtime functions - they're compile-time instructions that transform your code.
$state Transformation
What you write:
javascriptlet count = $state(0); count++;
What the compiler creates (conceptually):
javascriptlet count = { value: 0, subscribers: new Set(), get() { // Track who's reading if (currentEffect) { this.subscribers.add(currentEffect); } return this.value; }, set(newValue) { this.value = newValue; // Notify all subscribers this.subscribers.forEach(effect => effect.run()); } };
Every read/write to count is transformed to use these getters/setters.
$derived Transformation
What you write:
javascriptlet doubled = $derived(count * 2);
What happens:
- Compiler wraps the expression in a reactive computation
- When
countchanges, the computation re-runs - Only if the result differs, subscribers are notified
$effect Transformation
What you write:
javascript$effect(() => { console.log(count); });
What the compiler creates:
- Wraps your function as a "reactive scope"
- Tracks which reactive values are read during execution
- Re-runs the function when any dependency changes
- Handles cleanup when dependencies change or component unmounts
Why "Runes" and Not Functions?
Runes look like function calls, but they're actually compiler macros:
javascript// This doesn't work - $state isn't a real function! const createState = $state; // ā Error // Runes must be used directly let count = $state(0); // ā Compiler transforms this
The compiler sees $state(0) and transforms the entire variable declaration.
š Runes documentation