Stores vs Runes: When to Use Which

+15 Mana ✨

Svelte 5 prefers Runes, but stores still work. Here's how to choose and migrate.

Comparison

FeatureStoresRunes
APIsubscribe, set, updateDirect property access
Syntax$store prefixNo special syntax
File locationAny .js file.svelte.js files only
Learning curveHigherLower
TypeScriptGoodBetter
Library supportWideGrowing

Migration: writable to $state

Store way:

javascript
import { writable } from 'svelte/store';

export const count = writable(0);

// Usage in component
$count++;

Rune way:

javascript
// count.svelte.js
export const count = $state({ value: 0 });

// Usage in component
count.value++;

Migration: derived to $derived

Store way:

javascript
import { writable, derived } from 'svelte/store';

const count = writable(0);
const doubled = derived(count, $c => $c * 2);

Rune way:

javascript
// counter.svelte.js
let count = $state(0);
let doubled = $derived(count * 2);

export { count, doubled };

When Stores Still Make Sense

  1. Existing codebase: Don't rewrite working code just because
  2. Third-party libraries: Many still use stores
  3. Standard .js files: Runes require .svelte.js
  4. Complex subscriptions: Custom store logic

Custom Stores (Still Useful)

javascript
import { writable } from 'svelte/store';

function createPersisted(key, initial) {
  const stored = localStorage.getItem(key);
  const value = stored ? JSON.parse(stored) : initial;
  
  const { subscribe, set, update } = writable(value);
  
  return {
    subscribe,
    set: (v) => {
      localStorage.setItem(key, JSON.stringify(v));
      set(v);
    },
    update: (fn) => {
      update(v => {
        const newValue = fn(v);
        localStorage.setItem(key, JSON.stringify(newValue));
        return newValue;
      });
    }
  };
}

export const preferences = createPersisted('prefs', { theme: 'light' });

šŸ“– Stores documentation

āœ“ Completed