4 min read
I bundled the atom APIs on this box: Nanostores 1.5.4 came in at 1,280 B gzip against Jotai 3.0.1 vanilla at 2,708 B. On a 200-atom listen+bump loop, Nanostores ran about 7.6M updates/s and Jotai about 582k.
Short answer: pick Nanostores when you want a tiny, framework-agnostic atom store. Pick Jotai when you already live in React and want a large atom ecosystem. No affiliate links in this post.
| Browser build (esbuild minify) | Minified | gzip -9 |
|---|---|---|
| nanostores (atom, computed, onMount) | 2,556 B | 1,280 B |
| jotai/vanilla (atom, createStore) | 6,339 B | 2,708 B |
| nanostores + @nanostores/react (React external) | 2,775 B | 1,422 B |
| jotai React exports (React external) | 7,513 B | 3,283 B |
Nanostores was about 2.1× smaller gzip on the vanilla imports and about 2.3× smaller with the React hook. Disk trees were about 192 KB for nanostores against 360 KB for jotai. Track shipped weight with size-limit vs bundlesize. Unused-export cleanup after a swap: knip vs depcheck.
| Path (10,000 bumps, median of 9) | Nanostores | Jotai |
|---|---|---|
| 200 atoms + 1 listener each | 1.324 ms (7.56M/s) | 17.177 ms (582k/s) |
| Single atom + 1 listener | 0.944 ms (10.6M/s) | 13.737 ms (728k/s) |
| Derived pair (A+B→C) | 2.414 ms (4.14M/s) | 64.233 ms (156k/s) |
On this box Nanostores was roughly an order of magnitude faster on the multi-atom listen path. Framework harness notes sit next to my jsdom vs happy-dom write-up when I pull React into the loop.
| Situation | My pick |
|---|---|
| Astro / Solid / Vue / multi-framework UI | Nanostores |
| React-only app that already uses atoms | Jotai |
| Bundle budget under about 2 KB gzip for atoms | Nanostores |
| You need a deep React atom ecosystem | Jotai |
| Tiny store shared across islands | Nanostores |
Bottom line: Nanostores 1.5.4 shipped 1.3 KB gzip against Jotai 3.0.1 vanilla at 2.7 KB, and ran about 7.6M updates/s against 582k on a 200-atom fixture. Who should not switch: teams already deep in Jotai atoms and React helpers — rewrite cost beats a 1.4 KB gzip win. Lint the swap with Biome vs ESLint/Prettier. Test runner: Jest vs Vitest.
How this was made: I installed Nanostores and Jotai on the ShopperCove box, measured esbuild minify+gzip sizes (vanilla and React-external), timed store update loops, and recorded the JSON. The write-up was drafted with AI help and checked against that output.
Lab evidence
Hands-on on ShopperCove box 6 Oct 2026 ~00:55-00:57 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 22.20.0). nanostores 1.5.4 vs jotai 3.0.1, @nanostores/react 2.0.1, esbuild 0.28.2. Fixture /workspace/bench-nanostores-jotai/: vanilla entry atom+computed+onMount vs jotai/vanilla atom+createStore; React-external entries for useStore vs jotai hooks+Provider. Speed: 200 atoms with one listener each, 10,000 bumps x 9 rounds (median); simple single-atom; derived A+B→C. Medians: gzip 1,280 vs 2,708 B vanilla; 1,422 vs 3,283 B with React. 200-atom 1.324 vs 17.177 ms (7.56M vs 582k ups); simple 0.944 vs 13.737 ms; derived 2.414 vs 64.233 ms. Disk ~192 KB vs ~360 KB. Raw: res-bundle.json, res-store.json. Not tested: jotai Suspense/atomFamily, Nanostores persistent/map, SSR, real browsers, RN, DevTools. No affiliate. Distinct from jotai-vs-zustand (framework-agnostic atoms vs React store).