Updated Jul 16, 2026

01 - State ($state)

📋 Jump to Takeaways

🎁 Change one number and the screen updates by itself, with no re-render call and no setState. How does Svelte know that this exact variable is the one that changed?

What is $state?

$state() creates reactive state. When the value changes, the UI automatically updates. It replaces Svelte 4's implicit reactivity, where all top-level let variables were reactive.

Svelte 4 (Legacy)

<script>
let count = 0;  // all top-level let variables were automatically reactive
</script>

Svelte 5

<script>
let count = $state(0);  // explicitly opt-in to reactivity
</script>

The difference is that in Svelte 5, only variables wrapped in $state() are reactive. A plain let is just a regular JavaScript variable.

Basic Usage

<!-- src/lib/components/Counter.svelte -->
<script>
let count = $state(0);
</script>

<button onclick={() => count++}>Clicks: {count}</button>

Objects and Arrays

$state() has deep reactivity by default. Mutating nested properties or calling array methods automatically triggers UI updates.

<!-- src/lib/components/UserProfile.svelte -->
<script>
let user = $state({ name: 'Alice', age: 25 });
let items = $state([1, 2, 3]);
</script>

<button onclick={() => user.age++}>Birthday</button>  <!-- deep mutation tracked -->
<button onclick={() => items.push(items.length + 1)}>Add Item</button>  <!-- array mutation tracked -->

In Svelte 4, you had to reassign arrays and objects to trigger updates (items = [...items, newItem]). In Svelte 5, items.push() just works.

Interactive Example

<script>
let count = $state(0);
let user = $state({ name: 'Alice', age: 25 });
let items = $state([1, 2, 3]);
</script>

<div>
  <h2>01 - State Example</h2>
  
  <div>
    <h3>Counter</h3>
    <button onclick={() => count++}>Clicks: {count}</button>
    <button onclick={() => count = 0}>Reset</button>
  </div>
  
  <div>
    <h3>Object State</h3>
    <p>Name: {user.name}, Age: {user.age}</p>
    <button onclick={() => user.age++}>Birthday</button>
    <input bind:value={user.name} placeholder="Change name" />
  </div>
  
  <div>
    <h3>Array State</h3>
    <p>Items: {items.join(', ')}</p>
    <button onclick={() => items.push(items.length + 1)}>Add Item</button>
    <button onclick={() => items.pop()}>Remove Last</button>
  </div>
</div>

<style>
div { margin: 20px; }
h3 { margin-top: 20px; }
button { margin: 5px; }
</style>

Key Takeaways

  • Replaces Svelte 4's implicit reactivity. You now explicitly opt in with $state()
  • Works with primitives, objects, and arrays
  • Deep reactivity by default. Nested mutations are tracked automatically
  • Plain let without $state() is not reactive

🎁 You can store and mutate state now. But what about a value that's always calculated from other state, like a running total? Do you recompute it by hand every time it changes, or can Svelte keep it in sync for you?

📝 Ready to test your knowledge?

Answer the quiz below to mark this lesson complete.

Spot something off? Report an issue
© 2026 ByteLearn.dev. Free courses for developers. · Privacy