Skip to content

Introduction

Nano Kit is a lightweight, modular, and performant state management ecosystem for building modern web applications. Each library is designed to be small and tree-shakeable, while still offering rich DX and useful features.

import { signal, mountable, onMount, computed, effect } from '@nano_kit/store'
/* Create independent mountable atomic store */
const $count = mountable(signal(1))
/* Mountable: Run logic only when store has listeners */
onMount($count, () => {
console.log('Mounted: Store is active')
/* e.g., open websocket, start timer, etc. */
return () => {
console.log('Unmounted: Store is idle')
/* e.g., close websocket, stop timer */
}
})
/* Derive state (computed values are lazy & cached) */
const $double = computed(() => $count() * 2)
/* React to changes (triggers onMount) */
const unsub = effect(() => {
console.log(`Count: ${$count()}, Double: ${$double()}`)
})
/* Update triggers granular propagation */
$count(2)
/* Cleanup: removes listener and triggers onMount destructor */
unsub()
PackageDescription
@nano_kit/storeSignals-based state management library.
@nano_kit/queryData fetching and caching library, built on @nano_kit/store.
@nano_kit/routerRouting library, built on @nano_kit/store.
@nano_kit/ssrBase package for building framework-specific SSR adapters.
AdapterDescription
@nano_kit/reactReact integration for @nano_kit/store.
@nano_kit/react-routerReact integration for @nano_kit/router.
@nano_kit/react-ssrReact SSR adapter for @nano_kit/ssr.
@nano_kit/preactPreact integration for @nano_kit/store.
@nano_kit/preact-routerPreact integration for @nano_kit/router.
@nano_kit/preact-ssrPreact SSR adapter for @nano_kit/ssr.
@nano_kit/svelteSvelte integration for @nano_kit/store.
@nano_kit/svelte-routerSvelte integration for @nano_kit/router.
@nano_kit/svelte-ssrSvelte SSR adapter for @nano_kit/ssr.
@nano_kit/svelte-kitSvelteKit integration for stores, router, and SSR.
@nano_kit/next-routerNext.js integration for @nano_kit/router.

Nano Kit is built on the philosophy of Nano Stores and extends its core ideas:

  • Atomicity: Use independent, atomic stores for granular updates.
  • Mountable stores: Initialize resources only when the store is in use (on first listener) and clean up automatically.
  • Shift logic out of components: Move business logic to the store level.
  • Minimal footprint: Maintain a tiny core size that is fully tree-shakeable.

However, Nano Stores has some limitations:

  • Performance overhead
  • Suboptimal Developer Experience (DX)
  • Issues with SSR support

Nano Kit aims to fix these issues while keeping the same principles.

Adopting an ecosystem-first architecture provides a much smoother experience for developers than a stack of independent libraries. Because every part of the ecosystem is built on the same foundation, you get a consistent “feel” across the entire library. This shared core allows the tools to reuse internal logic, which drastically reduces your final bundle size.

Compare this to a standard setup like React Router + Redux + React Query. While these are great tools, they are effectively strangers to each other. They each have their own way of doing things and their own internal weight, often leading to duplicated code. Consequently, developers are forced to manually synchronize state and data between these independent tools inside the UI components, often resulting in bloated “glue code”.

Nano Kit takes a different approach. Because the router, data fetching, and state management layer are engineered to work together from day one, they integrate deeply at the store level. This removes the need for messy “glue code” in your components and keeps your application logic clean, unified, and efficient. It makes the store layer portable and independent, allowing you to easily swap the UI layer.

import { browserNavigation, searchParams, searchParam } from '@nano_kit/router'
import { client, queryKey } from '@nano_kit/query'
import { effect } from '@nano_kit/store'
import { useSignal } from '@nano_kit/react'
/* Router */
const [$location, navigation] = browserNavigation({ /* routes */ })
const $searchParams = searchParams($location)
const $page = searchParam($searchParams, 'page', v => (v ? Number(v) : 1))
/* Query */
const { query } = client()
const [
$episodes,
$episodesError,
$episodesLoading
] = query(queryKey('episodes'), [$page], async (page) => {
/* Fetcher automatically receives the current page */
return fetch(`/api/episodes?page=${page}`).then(r => r.json())
})
/* Logic is fully decoupled from UI components */
effect(() => {
console.log('Current page:', $page())
console.log('Episodes:', $episodes())
})
/* UI components remain pure and logic-free. Example (React): */
function MyComponent() {
const page = useSignal($page)
const episodes = useSignal($episodes)
/* ... */
}
/* Changing the URL updates $page signal and automatically triggers re-fetch */
navigation.push('/episodes?page=2')

To achieve high performance, Nano Kit uses the push-pull algorithm from alien-signals as the core of its reactivity system. A dedicated fork named “Agera” was created to support additional required features.

The benchmark results below show how @nano_kit/store (Agera) compares to other popular state management libraries.

LibraryLatency avg (ns)Latency med (ns)Throughput avg (ops/s)Throughput med (ops/s)Samples
alien-signals294.00
± 2.24%
270.00
± 0.00
3559763
± 0.01%
3703704
± 0
3401312
@nano_kit/store303.55
± 0.75%
290.00
± 0.00
3365816
± 0.01%
3448276
± 0
3294342
svelte/store428.58
± 0.61%
380.00
± 10.00
2479118
± 0.02%
2631579
± 67476
2333274
rxjs454.74
± 0.07%
430.00
± 0.00
2250397
± 0.01%
2325581
± 0
2199049
nanostores1373.2
± 5.96%
980.00
± 10.00
952399
± 0.04%
1020408
± 10520
728224
mobx3474.7
± 1.86%
3180.0
± 30.00
306094
± 0.03%
314465
± 2995
287796
valtio5041.3
± 11.46%
3820.0
± 160.00
254109
± 0.05%
261780
± 10699
198361
jotai9454.6
± 16.45%
6180.0
± 110.00
157853
± 0.05%
161812
± 2932
105769
effector24885
± 11.78%
15160
± 410.00
62744
± 0.15%
65963
± 1834
40186
@reatom/core59430
± 15.61%
41890
± 2429.0
22741
± 0.20%
23872
± 1438
16827

Benchmark was run on AMD Ryzen 5 PRO 3400G with Node.js v24.14.1

Comparison of bundle sizes for various implementations of the weather example:

StackRaw SizeGzipped Size
React + Nano Stores206.77 kB65.90 kB
React + Nano Kit211.32 kB67.25 kB
React + Nano Kit + DI212.49 kB67.60 kB
React + Reatom228.16 kB73.00 kB
React + TanStack Query232.63 kB72.42 kB

Bundled with Vite 8

Comparison of frontend bundle sizes for various SSR implementations of the rick-and-morty example:

StackRaw SizeGzipped SizeRaw Size
/characters page
React + Nano Kit SSR236.62 kB78.01 kB223.87 kB
React + TanStack Start374.95 kB117.43 kB364.59 kB
Next.js Pages Router + Nano Kit509.29 kB161.25 kB367.60 kB
Next.js App Router + Nano Kit946.14 kB292.69 kB470.21 kB

Bundled with Vite 8 / Next.js 16