DEV Community

Alex Spinov
Alex Spinov

Posted on

Nanostores Has a Free Framework-Agnostic State Manager — Here's How to Use It

Using React AND Svelte in your micro-frontend? Sharing state between them is a nightmare — unless you use Nanostores. One state library that works everywhere.

What Is Nanostores?

Nanostores is a tiny state manager (334 bytes!) that works with React, Vue, Svelte, Solid, Angular, and vanilla JS. Same atoms, any framework.

Quick Start

npm install nanostores @nanostores/react  # or @nanostores/vue, etc.
Enter fullscreen mode Exit fullscreen mode
// stores/counter.ts — framework-agnostic
import { atom, computed } from 'nanostores';

export const $count = atom(0);
export const $doubled = computed($count, count => count * 2);

export function increment() {
  $count.set($count.get() + 1);
}
Enter fullscreen mode Exit fullscreen mode

Use in React

import { useStore } from '@nanostores/react';
import { $count, $doubled, increment } from '../stores/counter';

function Counter() {
  const count = useStore($count);
  const doubled = useStore($doubled);

  return (
    <div>
      <p>{count} (doubled: {doubled})</p>
      <button onClick={increment}>+1</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Use in Svelte

<script>
import { $count, $doubled, increment } from '../stores/counter';
</script>

<p>{$count} (doubled: {$doubled})</p>
<button on:click={increment}>+1</button>
Enter fullscreen mode Exit fullscreen mode

Use in Vue

<script setup>
import { useStore } from '@nanostores/vue';
import { $count, $doubled, increment } from '../stores/counter';

const count = useStore($count);
const doubled = useStore($doubled);
</script>

<template>
  <p>{{ count }} (doubled: {{ doubled }})</p>
  <button @click="increment">+1</button>
</template>
Enter fullscreen mode Exit fullscreen mode

Why Nanostores

Feature Nanostores Zustand Pinia Svelte stores
Size 334B 1KB 2KB Built-in
React Yes Yes No No
Vue Yes No Yes No
Svelte Yes No No Yes
Solid Yes No No No
Astro Yes Partial No Partial

Async Data

import { atom, onMount } from 'nanostores';

export const $users = atom([]);
export const $loading = atom(false);

onMount($users, () => {
  $loading.set(true);
  fetch('/api/users')
    .then(r => r.json())
    .then(users => {
      $users.set(users);
      $loading.set(false);
    });
});
Enter fullscreen mode Exit fullscreen mode

Maps (Object State)

import { map } from 'nanostores';

export const $settings = map({
  theme: 'light',
  language: 'en',
  notifications: true,
});

// Update single key without spreading
$settings.setKey('theme', 'dark');
Enter fullscreen mode Exit fullscreen mode

Perfect For

  • Astro islands — share state between framework components
  • Micro-frontends — common state across React/Vue/Svelte
  • Migration — gradually move from one framework to another
  • Libraries — ship with framework-agnostic state

Get Started


Building a multi-framework app? My Apify scrapers provide data for any frontend. Custom solutions: spinov001@gmail.com

Top comments (0)