v3 migration
Roadmap: https://github.com/pmndrs/jotai/discussions/2889
Jotai v3 focuses on modernizing the package. The core API and its behavior are unchanged. If your app runs on Jotai v2 without deprecation warnings, it should run on v3 as is.
Requirement changes
The minimum requirements are raised:
- React 18 (v2 supports React 17)
- TypeScript 5.5 (v2 supports TypeScript 3.8)
- Node.js
^20.19.0 || >=22.12.0(v2 supports Node.js 12.20)
Packaging changes
ESM only
The CJS, UMD and SystemJS builds are no longer provided.
Modern bundlers work with the ESM build out of the box.
The supported Node.js versions can load it
even from CJS code with require().
The package exports only expose the public entry points:
jotaijotai/utilsjotai/vanillajotai/vanilla/utilsjotai/vanilla/internalsjotai/reactjotai/react/utils
Importing other files in the package directly no longer works.
process.env.NODE_ENV is used directly
The published files read process.env.NODE_ENV directly
to omit development-only checks in production.
Bundlers handle it by default.
If you load Jotai in a browser without a bundler
(for example, with import maps),
you need to define it by yourself.
globalThis.process ??= { env: { NODE_ENV: 'production' } }
ES2020 syntax
The published files are compiled with the ES2020 target. If you need to support older browsers, transpile the package in your build.
Removed features
atomFamily util
It's moved to the jotai-family package.
Previous API
import { atomFamily } from 'jotai/utils'
New API
// npm install jotai-familyimport { atomFamily } from 'jotai-family'
loadable util
Use the unwrap util instead.
The previous behavior can be implemented in userland:
import { atom } from 'jotai'import { unwrap } from 'jotai/utils'function loadable(anAtom) {const LOADING = { state: 'loading' }const unwrappedAtom = unwrap(anAtom, () => LOADING)return atom((get) => {try {const data = get(unwrappedAtom)if (data === LOADING) {return LOADING}return { state: 'hasData', data }} catch (error) {return { state: 'hasError', error }}})}
jotai/babel plugins
They are moved to the jotai-babel package.
Previous API
// babel configplugins: ['jotai/babel/plugin-react-refresh']
New API
// npm install jotai-babelplugins: ['jotai-babel/plugin-react-refresh']
setSelf option in the read function
Previous API
const anAtom = atom(async (get, { setSelf }) => {// ...})
New API
There is no direct replacement.
Depending on the use case,
onMount or jotai-effect
would cover it.
delay option in useAtom and useAtomValue
Previous API
const value = useAtomValue(anAtom, { delay: 100 })
New API
Create a custom hook:
import { useEffect, useState } from 'react'import { useStore } from 'jotai'function useAtomValueWithDelay(anAtom, { delay }) {const store = useStore()const [value, setValue] = useState(() => store.get(anAtom))useEffect(() => {const unsub = store.sub(anAtom, () => {setTimeout(() => setValue(store.get(anAtom)), delay)})return unsub}, [store, anAtom, delay])return value}
New hooks for advanced users
v3 adds useAtomValueRaw
and useAtomValueRawSync,
which don't resolve promises.
They are not required for migration,
but they are escape hatches when the default useAtomValue behavior
with async atoms doesn't fit your use case.