Jotai is a primitive and flexible state management library for React built around atoms. Each atom holds one piece of state, and any component can read or update it with a hook. Atoms can also derive from other atoms, so one value stays in sync with another automatically.
Install Jotai
Jotai ships as a single package with a tiny API. Install it in any React project, including Vite and Next.js.
npm install jotaiThe core API is two functions: atom defines a value and useAtom reads and updates it. Basic usage needs no provider, so there is nothing to wrap at the root.
Create and read an atom
An atom starts with an initial value. useAtom returns the current value and a setter, much like useState, but the atom is shared across the whole app.
import { atom, useAtom } from "jotai";
const countAtom = atom(0);
export function Counter() {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<button onClick={() => setCount((c) => c + 1)}>+</button>
<span>{count}</span>
</div>
);
}Clicking the button increments the atom, and every component that reads countAtom re-renders with the new value. The setter accepts a function, which is the safe way to update based on the previous value. The atom object itself is stable, so passing it around never causes a re-render by itself.
Atoms vs component state
Component state stays inside one component. An atom lives outside the component tree, so two components that read the same atom always see the same value.
Think of an atom as a small, single value store. Where useState keeps a value local, an atom keeps it shared without any context or prop setup. That makes atoms a good middle step between lifting state and adopting a full store.
Share one atom across components
Because the atom is defined once and imported, two components stay in sync without lifting state or passing props.
function Display() {
const [count] = useAtom(countAtom);
return <p>Current count: {count}</p>;
}When Counter increments the atom, Display updates too. There is no prop drilling and no context wrapper, because the atom is the shared source of truth.
Update an atom from anywhere
The setter returned by useAtom is the same no matter which component calls it. A button deep in the tree can update an atom that a header reads, with no callback prop passed between them.
Derive values from atoms
A derived atom reads other atoms with get and computes a value from them. It has no setter of its own.
const doubledAtom = atom((get) => get(countAtom) * 2);
function Doubled() {
const [doubled] = useAtom(doubledAtom);
return <p>Doubled: {doubled}</p>;
}When countAtom changes, doubledAtom recomputes, and Doubled re-renders with the new value. Jotai tracks the dependency automatically, so you never update a derived value by hand. Derived atoms stay read-only, which keeps the data flow one directional and easy to follow.
Write to multiple atoms
A writable derived atom can update several atoms in one call. Its write function receives get and set, plus any arguments the caller passes.
const priceAtom = atom(10);
const discountedAtom = atom(
(get) => get(priceAtom),
(get, set, discount) => set(priceAtom, get(priceAtom) - discount)
);The second argument to atom is the write function, called when a component sets discountedAtom. It reads the current price and writes the reduced value back. This is how one action can update several related atoms in a single place.
When Jotai is the right fit
Jotai fits fine grained state where many small values derive from each other. It also shines for derived values that change as other values change, like a cart total.
It is less useful for one big store with a rigid shape, where Redux Toolkit or Zustand may fit better. A broader comparison is in the state management decision guide.
The split between client and server data is separate from this choice. Jotai manages client state, while server cache belongs in a data library, as client state vs server state in React explains.
For values that never leave one component, see how to avoid global state when local state is enough. For most small apps, a few atoms are all the shared state you need.
Rune AI
Key Insights
- Install jotai and import atom and useAtom.
- Create a shared value with atom and an initial value.
- Read and update it with useAtom in any component.
- Build derived atoms with a read function that uses get.
Frequently Asked Questions
Does Jotai need a Provider?
What is the difference between an atom and useState?
What is a derived atom?
Conclusion
Jotai models state as small atoms. Create an atom with atom, read and update it with useAtom, and build derived atoms that recompute from their dependencies.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.