ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 93

  1. Blog

Nanostores vs Jotai: 1.3 KB vs 2.7 KB Gzip

Aditya Challa·5 October 2026·4 min read

Hands-on
On this page
  1. What I tested
  2. How wide was the size gap?
  3. How fast were the updates?
  4. Which one should you pick?
  5. Sources
  6. Related

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.

What I tested

  • Machine: 8 vCPU Intel Xeon / 15 GB RAM shared Linux cloud box, tested 6 Oct 2026 about 00:55–00:57 IST.
  • Versions: nanostores 1.5.4, jotai 3.0.1, @nanostores/react 2.0.1, React external for the React-binding size check, Node 22.20.0, esbuild 0.28.2 minify + gzip -9.
  • Fixture: /workspace/bench-nanostores-jotai/. Vanilla size: nanostores atom+computed+onMount vs jotai/vanilla atom+createStore. React size: nanostores+useStore vs jotai atom+useAtomValue+useSetAtom+Provider with React external. Speed: 200 atoms each with one listener, 10,000 bumps × 9 rounds (median); plus a simple single-atom path and a two-atom derived path.
  • Findings: gzip 1,280 B vs 2,708 B (vanilla); with React bindings 1,422 B vs 3,283 B. Median 200-atom loop 1.324 ms vs 17.177 ms for 10k bumps (about 7.56M vs 582k updates/s). Simple path about 10.6M vs 728k updates/s.
  • One surprise: the derived-pair path widened the gap further (about 4.1M vs 156k updates/s). Nanostores stayed cheaper when a computed sat on top of two atoms.
  • Not tested: jotai React Suspense helpers, atomFamily, Nanostores persistent/map stores, SSR hydration, real browsers, React Native, DevTools. This is not a re-run of jotai vs Zustand (different intent).

How wide was the size gap?

Browser build (esbuild minify)Minifiedgzip -9
nanostores (atom, computed, onMount)2,556 B1,280 B
jotai/vanilla (atom, createStore)6,339 B2,708 B
nanostores + @nanostores/react (React external)2,775 B1,422 B
jotai React exports (React external)7,513 B3,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.

How fast were the updates?

Path (10,000 bumps, median of 9)NanostoresJotai
200 atoms + 1 listener each1.324 ms (7.56M/s)17.177 ms (582k/s)
Single atom + 1 listener0.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.

Which one should you pick?

SituationMy pick
Astro / Solid / Vue / multi-framework UINanostores
React-only app that already uses atomsJotai
Bundle budget under about 2 KB gzip for atomsNanostores
You need a deep React atom ecosystemJotai
Tiny store shared across islandsNanostores

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.

Sources

  • https://github.com/nanostores/nanostores
  • https://www.npmjs.com/package/nanostores
  • https://jotai.org/
  • https://www.npmjs.com/package/jotai

Related

  • https://www.shoppercove.com/blog/size-limit-vs-bundlesize
  • https://www.shoppercove.com/blog/knip-vs-depcheck
  • https://www.shoppercove.com/blog/jsdom-vs-happy-dom-vitest
  • https://www.shoppercove.com/blog/jest-vs-vitest
  • https://www.shoppercove.com/blog/biome-vs-eslint-prettier
  • https://www.shoppercove.com/blog/oxlint-vs-eslint
  • https://www.shoppercove.com/blog/lightningcss-vs-postcss
  • https://www.shoppercove.com/blog/vite-vs-parcel
nanostoresjotaistate managementreactperformance benchmarkbundle sizeatoms

Lab evidence

What I found running this

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).

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Related links

  • Plate 66

    Jotai vs Zustand: 0.15 ms vs 0.17 ms per Update

    5 Oct 2026

  • Plate 38

    TanStack Query vs SWR: 10.4 KB vs 5.6 KB Gzip

    5 Oct 2026

  • Plate 60

    Zustand vs Redux Toolkit: 0.14 ms vs 0.68 ms per Update

    zustand 5.0.15 vs @reduxjs/toolkit 2.13.0 + react-redux 9.3.0 on React 19.3.0 (jsdom, NODE_ENV=production). 1,000 selector-subscribed rows, 300 flushSync updates x 7 trials, 2 runs: per-update median 0.137/0.139 ms vs 0.676/0.694 ms (~5x); 1 row re-rendered per update in both. Store-only: 1,376,191 vs 6,502 updates/s; Immer autoFreeze off lifts RTK to 386,966. Gzip (React external): 387 B vs 9,708 B. Fixture /workspace/bench-zustand-rtk/.

    5 Oct 2026

On this page

  1. What I tested
  2. How wide was the size gap?
  3. How fast were the updates?
  4. Which one should you pick?
  5. Sources
  6. Related
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove