Deep vs Shallow Reactivity

+15 Mana ✨

When you wrap a value with $state, Svelte creates a deeply reactive proxy. This has important implications.

Deep Proxies

js
let user = $state({
  name: 'Alice',
  address: {
    city: 'New York',
    zip: '10001'
  },
  hobbies: ['reading', 'coding']
});

All of these trigger updates:

js
user.name = 'Bob';              // ✅ Tracked
user.address.city = 'Boston';   // ✅ Tracked (nested!)
user.hobbies.push('gaming');    // ✅ Tracked (array mutation!)
user.hobbies[0] = 'writing';    // ✅ Tracked (index assignment!)

This is a HUGE improvement over Svelte 4, where only top-level reassignments were tracked.

Fine-Grained Tracking

Svelte tracks which specific properties are accessed:

svelte
<script>
  let user = $state({
    name: 'Alice',
    email: 'alice@example.com'
  });
</script>

<!-- This component only re-renders when user.name changes -->
<p>Hello, {user.name}!</p>

<!-- Changing user.email won't cause the above to update -->

$state.raw: Opting Out of Deep Reactivity

Sometimes you don't want deep proxying — for large objects or third-party instances:

js
// Large dataset: don't proxy every property
let bigData = $state.raw(hugeDataset);

// Third-party object: proxying might break it
let map = $state.raw(new google.maps.Map());

With $state.raw, only reassigning the variable triggers updates:

js
bigData.items[0].value = 'new';  // ❌ NOT tracked
bigData = { ...bigData };         // ✅ Tracked (reassignment)

$state.snapshot: Getting Plain Objects

Sometimes you need the raw, non-proxied value (e.g., for JSON.stringify or sending to an API):

js
let user = $state({ name: 'Alice' });

// Get a plain object copy
const plain = $state.snapshot(user);
console.log(plain);  // { name: 'Alice' } — not a proxy

// Useful for:
await fetch('/api/user', {
  body: JSON.stringify($state.snapshot(user))
});

When to Use What

ScenarioUse
Most state$state()
Large, rarely-changing data$state.raw()
Third-party object instances$state.raw()
Passing to external APIs$state.snapshot()
✓ Completed