Skip to main content
Deno 2 is finally here 🎉️
Learn more
Module

x/jotai/docs/guides/nextjs.mdx

👻 Primitive and flexible state management for React
Latest
File
---title: Next.jsdescription: How to use Jotai with Next.jsnav: 7.03keywords: next,nextjs---
### Hydration
Jotai has support for hydration of atoms with `useHydrateAtoms`. The documentation for the hook can be seen [here](../utilities/ssr.mdx).
### Sync with router
It's possible to sync Jotai with the router. You can achieve this with `atomWithHash`:
```jsconst pageAtom = atomWithHash('page', 1, { replaceState: true, subscribe: (callback) => { Router.events.on('routeChangeComplete', callback) window.addEventListener('hashchange', callback) return () => { Router.events.off('routeChangeComplete', callback) window.removeEventListener('hashchange', callback) } },})```
This way you have full control over what [router event](https://nextjs.org/docs/api-reference/next/router#routerevents) you want to subscribe to.
> #### In Next.js 13>> As of Next.js 13 there have been some changes to the `Router.events.on()` which no longer expose events. There are plans in the [App Router Roadmap](https://beta.nextjs.org/docs/app-directory-roadmap#planned-features) for event intercepting and hash handeling. However there is no ETA on when this will be available or what it will look like. For now when trying to the `atomWithHash()` you will not get the atom loading with any data when navigating using the router, only when the page is reloaded or the component is rerendered. It is also recommended that you set the `setHash` option to `replaceState` as Next.js appears to use window.history in the background and this will allow the user to use the browser back button.### You can't return promises in server side rendering
It's important to note that you can't return promises with SSR - However, it's possible to guard against it inside the atom definition.
If possible use `useHydrateAtoms` to hydrate values from the server.
```jsconst postData = atom((get) => { const id = get(postId) if (isSSR || prefetchedPostData[id]) { return prefetchedPostData[id] || EMPTY_POST_DATA } return fetchData(id) // returns a promise})```
### Provider
By default, Jotai uses an implicit global store to keep track of atom values. This is what is referred to as "provider-less" mode. This becomes an issue in SSR scenario because this global store is kept alive and is shared between multiple requests, which can lead to bugs and security risks.
To limit the lifetime of the store to the scope of one request, you need to use a [Provider](../core/provider.mdx) at the root of your app (or a subtree if you're using Jotai only for a part of your application).
```typescriptimport { Provider } from 'jotai'
function App({ Component, pageProps }: AppProps) { return ( <Provider> <Component {...pageProps} /> </Provider> )}```
In this case:
1. `Provider` will hold the state of the atoms used in its subtree instead of the global store.2. `Provider`'s lifetime will be the same as the app itself, and since the app is recreated on each SSR request we essentially limit the lifetime of the store to a single request as well.
### SWC plugins
Jotai provides SWC plugins for better DX while developing with Next.js. [Find more info in the SWC section.](../tools/swc.mdx)
### Examples
#### Clock
<Stackblitz id="stackblitz-starters-nsugnt" file="store%2Findex.ts,components%2FClock.tsx"/>
#### HN Posts
Page Router demo:
<Stackblitz id="stackblitz-starters-cnz9lg" file="store%2Findex.ts,pages%2F_app.tsx,pages%2Findex.tsx"/>
App Router [demo on Stackblitz](https://stackblitz.com/edit/jotai-nextjs-app-router-demo?file=store%2Findex.ts,app%2Flayout.tsx,components%2FPost.tsx,app%2Fpage.tsx)
#### Next.js repo
```bashnpx create-next-app --example with-jotai with-jotai-app```
Here's a [link](https://github.com/vercel/next.js/tree/canary/examples/with-jotai).