Skip to content

Svelte Stores

When React state needs to be shared across components, you reach for Context + useReducer, Redux, or Zustand. Svelte has built-in stores that cover the same ground with no extra packages:

  • writable(initial) — any component can read and write
  • readable(initial, start) — read-only; an external source (timer, WebSocket) drives updates
  • derived(stores, fn) — computed from one or more stores, updates automatically

The magic is the $ prefix in markup. Writing {$count} in a Svelte template auto-subscribes the component to the store and auto-unsubscribes when the component is destroyed. In plain JS (outside a .svelte file) you call .subscribe() manually.

React
// store.ts (Zustand)
import { create } from 'zustand';
export const useCountStore = create(set => ({
count: 0,
increment: () => set(s => ({ count: s.count + 1 })),
reset: () => set({ count: 0 }),
}));
// Counter.tsx
function Counter() {
const { count, increment, reset } = useCountStore();
return (
<>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={reset}>Reset</button>
</>
);
}
Svelte
<!-- stores.ts -->
import { writable } from 'svelte/store';
export const count = writable(0);
<!-- Counter.svelte -->
<script>
import { count } from './stores.ts';
</script>
<p>Count: {$count}</p>
<button onclick={() => count.update(n => n + 1)}>+</button>
<button onclick={() => count.set(0)}>Reset</button>

A writable store exposes three methods: .set(value) to replace, .update(fn) to transform, and .subscribe(fn) to listen manually. In .svelte markup, the $ prefix handles subscribe/unsubscribe for you.

React
// With Zustand selector
const double = useCountStore(s => s.count * 2);
// Or with useMemo in a component
const double = React.useMemo(() => count * 2, [count]);
Svelte
import { writable, derived } from 'svelte/store';
export const count = writable(0);
// Derived store — updates whenever count changes
export const doubleCount = derived(count, $count => $count * 2);
// In a component:
// {$doubleCount} ← auto-subscribed

derived works with multiple source stores too: derived([a, b], ([$a, $b]) => $a + $b).

What does the $ prefix do when you write {$count} in Svelte markup?
Which Svelte store type is most analogous to React's useMemo or a Zustand selector?
When does Svelte automatically unsubscribe a component from a store it reads with $?