Next.js
There is no dedicated package for Next.js apps. Use @nano_kit/react for signals, Dependency Injection, and hydration. If your app also uses @nano_kit/router, add @nano_kit/next-router.
For detailed API reference, see the React integration and Next.js Router integration.
Installation
Section titled “Installation”Install @nano_kit/store and @nano_kit/react for the base React integration. Add @nano_kit/router and @nano_kit/next-router only when you use Nano Kit router.
pnpm add @nano_kit/store @nano_kit/react# If you use Nano Kit router:pnpm add @nano_kit/router @nano_kit/next-routeryarn add @nano_kit/store @nano_kit/react# If you use Nano Kit router:yarn add @nano_kit/router @nano_kit/next-routernpm install @nano_kit/store @nano_kit/react# If you use Nano Kit router:npm install @nano_kit/router @nano_kit/next-routerApp Router
Section titled “App Router”In the App Router there are two different setups:
- Flight dehydration: use
Dehydrationwhen server dehydration should run both on the initial request and on RSC flight navigations. - Static dehydration: use
StaticDehydrationwhen dehydration should run only on the initial full-page request. During client-side navigations, stores will fetch data in the browser instead of on the server.
Both dehydration components can be nested and repeated. It is valid to dehydrate shared stores in a layout and page-specific stores in a page.
Flight Dehydration
Section titled “Flight Dehydration”In this mode, FlightDetector is not needed. Keep HydrationProvider in the root layout. If you use @nano_kit/router, wrap the layout with NextNavigation. Without the router, omit NextNavigation.
import type { Metadata } from 'next'import { HydrationProvider } from '@nano_kit/react'import { NextNavigation } from '@nano_kit/next-router'import { routes } from '@/stores/router'
/* Define global routes types */declare module '@nano_kit/router' { interface AppContext { routes: typeof routes }}
export const metadata: Metadata = { title: 'My App'}
export default function RootLayout({ children }: { children: React.ReactNode}) { return ( <NextNavigation routes={routes}> <HydrationProvider> <html lang='en'> <body>{children}</body> </html> </HydrationProvider> </NextNavigation> )}In page components, use Dehydration. If the page uses @nano_kit/router, wrap the dehydration boundary in its own NextNavigation so flight renders still receive the current navigation context.
import { Dehydration } from '@nano_kit/react'import { NextNavigation } from '@nano_kit/next-router'import { routes } from '@/stores/router'import CharactersPage, { Stores$ } from '@/ui/pages/Characters'
export default function Page() { return ( <NextNavigation routes={routes}> <Dehydration stores={Stores$}> <CharactersPage /> </Dehydration> </NextNavigation> )}If you do not use @nano_kit/router, render Dehydration directly without NextNavigation.
Static Dehydration
Section titled “Static Dehydration”In this mode, add FlightDetector to the root layout so StaticDehydration can distinguish the initial full-page request from RSC flight navigations. Keep HydrationProvider in the layout as well.
If you use @nano_kit/router, wrap the layout with NextNavigation. Without the router, omit NextNavigation.
import type { Metadata } from 'next'import { FlightDetector, HydrationProvider} from '@nano_kit/react'import { NextNavigation } from '@nano_kit/next-router'import { routes } from '@/stores/router'
/* Define global routes types */declare module '@nano_kit/router' { interface AppContext { routes: typeof routes }}
export const metadata: Metadata = { title: 'My App'}
export default function RootLayout({ children }: { children: React.ReactNode}) { return ( <FlightDetector> <NextNavigation routes={routes}> <HydrationProvider> <html lang='en'> <body>{children}</body> </html> </HydrationProvider> </NextNavigation> </FlightDetector> )}In page components, use StaticDehydration. If the page uses @nano_kit/router, wrap the dehydration boundary in its own NextNavigation.
import { StaticDehydration } from '@nano_kit/react'import { NextNavigation } from '@nano_kit/next-router'import { routes } from '@/stores/router'import CharactersPage, { Stores$ } from '@/ui/pages/Characters'
export default function Page() { return ( <NextNavigation routes={routes}> <StaticDehydration stores={Stores$}> <CharactersPage /> </StaticDehydration> </NextNavigation> )}If you do not use @nano_kit/router, render StaticDehydration directly without NextNavigation.
Pages Router
Section titled “Pages Router”In the Pages Router, the usual setup is:
HydrationProviderin_app.tsxdehydrate()orcontextDehydrate()ingetServerSidePropsNextNavigationProviderwhen the app uses@nano_kit/router
_app.tsx
Section titled “_app.tsx”If you use @nano_kit/router, wrap the app with NextNavigationProvider. Without the router, keep only HydrationProvider.
import type { AppProps } from 'next/app'import { HydrationProvider } from '@nano_kit/react'import { NextNavigationProvider } from '@nano_kit/next-router'import { routes } from '@/stores/router'
/* Define global routes types */declare module '@nano_kit/router' { interface AppContext { routes: typeof routes }}
export default function App({ Component, pageProps }: AppProps) { return ( <NextNavigationProvider routes={routes}> <HydrationProvider dehydrated={pageProps.dehydrated}> <Component {...pageProps} /> </HydrationProvider> </NextNavigationProvider> )}getServerSideProps
Section titled “getServerSideProps”When you need server-prefetched store data, dehydrate stores in getServerSideProps and pass the snapshot through pageProps.dehydrated.
If the page uses @nano_kit/router, create the dehydration context with virtualNavigationContext.
import type { GetServerSideProps } from 'next'import { dehydrate } from '@nano_kit/store'import { virtualNavigationContext } from '@nano_kit/next-router'import { routes } from '@/stores/router'import CharactersPage, { Stores$ } from '@/ui/pages/Characters'
export const getServerSideProps: GetServerSideProps = async (context) => { const dehydrated = await dehydrate( Stores$, virtualNavigationContext(context.resolvedUrl, routes) )
return { props: { dehydrated } }}
export default function Page() { return <CharactersPage />}If you want the Pages Router to behave like static dehydration in the App Router, use isFlight(context.req.headers) and skip dehydration during client-side navigations. In that case, stores will fetch data in the browser instead of on the server.
import type { GetServerSideProps } from 'next'import { dehydrate } from '@nano_kit/store'import { isFlight } from '@nano_kit/react'import { virtualNavigationContext } from '@nano_kit/next-router'import { routes } from '@/stores/router'import CharactersPage, { Stores$ } from '@/ui/pages/Characters'
export const getServerSideProps: GetServerSideProps = async (context) => { const dehydrated = !isFlight(context.req.headers) && await dehydrate( Stores$, virtualNavigationContext(context.resolvedUrl, routes) )
return { props: { dehydrated } }}
export default function Page() { return <CharactersPage />}Without @nano_kit/router, call dehydrate(Stores$) without virtualNavigationContext.
Which Package Does What?
Section titled “Which Package Does What?”@nano_kit/reacthandles React bindings, DI integration,HydrationProvider,Dehydration,StaticDehydration, andFlightDetector.@nano_kit/next-routeris only needed when the app uses@nano_kit/routerinside Next.js.@nano_kit/routerremains the place where routes, pages, layouts, and navigation logic are declared.
If you need API-level details for NextNavigation, NextNavigationProvider, Link, or Pages Router helpers such as redirect() and notFound(), see Next.js Router integration.