Skip to main content
The Provider component creates a store scope for atoms. All hooks under a Provider will use the same store instance, isolating atom state from other parts of the app.

Signature

function Provider({
  children,
  store,
}: {
  children?: ReactNode
  store?: Store
}): ReactElement

Parameters

children
ReactNode
React children that will have access to the Provider’s store.
store
Store
A custom store instance created with createStore(). If not provided, a new store will be created automatically.

Returns

element
ReactElement
A React element that provides the store context to its children.

Examples

Basic Usage

import { Provider } from 'jotai'
import { App } from './App'

function Root() {
  return (
    <Provider>
      <App />
    </Provider>
  )
}

With Custom Store

import { Provider, createStore } from 'jotai'
import { App } from './App'

const myStore = createStore()

function Root() {
  return (
    <Provider store={myStore}>
      <App />
    </Provider>
  )
}

Multiple Isolated Stores

import { Provider, atom, useAtom } from 'jotai'

const countAtom = atom(0)

function Counter() {
  const [count, setCount] = useAtom(countAtom)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>Increment</button>
    </div>
  )
}

function App() {
  return (
    <div>
      <h2>Store 1</h2>
      <Provider>
        <Counter />
      </Provider>

      <h2>Store 2</h2>
      <Provider>
        <Counter />
      </Provider>
    </div>
  )
}
// Each Provider has its own independent count state

Nested Providers

import { Provider, atom, useAtom } from 'jotai'

const themeAtom = atom('light')
const userAtom = atom({ name: 'Guest' })

function ThemedContent() {
  const [theme] = useAtom(themeAtom)
  const [user] = useAtom(userAtom)

  return (
    <div className={theme}>
      Welcome, {user.name}!
    </div>
  )
}

function App() {
  return (
    <Provider>
      {/* Global theme */}
      <Provider>
        {/* Scoped user state */}
        <ThemedContent />
      </Provider>
    </Provider>
  )
}

Reusing Store Across Components

import { Provider, createStore, atom } from 'jotai'

const countAtom = atom(0)
const myStore = createStore()

// Initialize store
myStore.set(countAtom, 10)

function App() {
  return (
    <Provider store={myStore}>
      <Counter />
    </Provider>
  )
}

Server-Side Rendering (SSR)

import { Provider, createStore, atom } from 'jotai'

const userAtom = atom({ name: 'Unknown' })

function App({ initialUserData }) {
  // Create a new store for each request
  const store = createStore()

  // Hydrate initial state
  store.set(userAtom, initialUserData)

  return (
    <Provider store={store}>
      <UserProfile />
    </Provider>
  )
}

Testing with Isolated State

import { Provider, atom, useAtom } from 'jotai'
import { render, screen } from '@testing-library/react'

const countAtom = atom(0)

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  return (
    <div>
      <span>Count: {count}</span>
      <button onClick={() => setCount((c) => c + 1)}>Increment</button>
    </div>
  )
}

test('counter increments', () => {
  // Each test gets a fresh store
  render(
    <Provider>
      <Counter />
    </Provider>
  )

  expect(screen.getByText('Count: 0')).toBeInTheDocument()
})

Without Provider (Default Store)

import { atom, useAtom } from 'jotai'

const countAtom = atom(0)

function Counter() {
  // Uses the default global store
  const [count, setCount] = useAtom(countAtom)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>Increment</button>
    </div>
  )
}

function App() {
  return <Counter />
}
// No Provider needed, but state is global across the entire app

Notes

  • Provider is optional. Without a Provider, atoms use a default global store via getDefaultStore()
  • Each Provider creates an isolated store scope - atoms in different Providers don’t share state
  • Providers can be nested - the closest Provider wins
  • If you pass a custom store, it will be reused across re-renders
  • If you don’t pass a store, a new store is created once using useRef and persists across re-renders
  • Provider is essential for SSR to ensure each request gets its own state
  • Useful for testing to ensure test isolation

useStore Hook

The useStore hook returns the store from the nearest Provider ancestor, or the default store if no Provider exists.

Signature

function useStore(options?: { store?: Store }): Store

Usage

import { useStore } from 'jotai'

function MyComponent() {
  const store = useStore()
  
  // Use the store imperatively
  const count = store.get(countAtom)
  store.set(countAtom, count + 1)
}

With options

import { useStore, createStore } from 'jotai'

const customStore = createStore()

function MyComponent() {
  // Force using a specific store
  const store = useStore({ store: customStore })
}

Build docs developers (and LLMs) love