Skip to main content
Jotai works perfectly with Vite. This guide shows you how to enhance your development experience using Vite-specific plugins.

Quick Start

1

Create Vite project

npm create vite@latest my-app -- --template react-ts
cd my-app
2

Install Jotai

npm install jotai
3

Install Babel plugins (optional)

For better DX, install Jotai’s Babel plugins:
npm install --save-dev jotai-babel

Babel Plugin Configuration

Enhance your developer experience with Jotai’s Babel plugins:
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import jotaiDebugLabel from 'jotai-babel/plugin-debug-label'
import jotaiReactRefresh from 'jotai-babel/plugin-react-refresh'

export default defineConfig({
  plugins: [
    react({ 
      babel: { 
        plugins: [jotaiDebugLabel, jotaiReactRefresh] 
      } 
    }),
  ],
})

What These Plugins Do

debug-label Plugin

Automatically adds debug labels to atoms for better DevTools experience:
// You write:
const countAtom = atom(0)

// Plugin transforms to:
const countAtom = atom(0)
countAtom.debugLabel = 'countAtom'

react-refresh Plugin

Enables React Fast Refresh for atoms, preserving state during hot module replacement:
// Atoms maintain their state when you edit code
const countAtom = atom(0)
// Edit this file, count value persists!

TypeScript Configuration

Ensure your tsconfig.json is configured for optimal Jotai usage:
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

Example App Structure

my-vite-app/
├── src/
│   ├── atoms/
│   │   └── index.ts
│   ├── components/
│   │   └── Counter.tsx
│   ├── App.tsx
│   └── main.tsx
├── vite.config.ts
└── package.json

Example Files

// src/atoms/index.ts
import { atom } from 'jotai'

export const countAtom = atom(0)
export const doubleCountAtom = atom((get) => get(countAtom) * 2)
// src/components/Counter.tsx
import { useAtom } from 'jotai'
import { countAtom, doubleCountAtom } from '../atoms'

export function Counter() {
  const [count, setCount] = useAtom(countAtom)
  const [doubleCount] = useAtom(doubleCountAtom)
  
  return (
    <div>
      <h1>Count: {count}</h1>
      <h2>Double: {doubleCount}</h2>
      <button onClick={() => setCount(c => c + 1)}>
        Increment
      </button>
    </div>
  )
}
// src/App.tsx
import { Counter } from './components/Counter'

function App() {
  return (
    <div className="App">
      <Counter />
    </div>
  )
}

export default App

Development

Start the development server:
npm run dev
With the Babel plugins configured, you’ll get:
  • Automatic debug labels in React DevTools
  • Fast Refresh that preserves atom state
  • Better debugging experience

Production Build

Build for production:
npm run build
The Babel plugins are safe for production - debug labels are useful for debugging production issues.

Environment Variables

Access environment variables in atoms:
import { atom } from 'jotai'

const apiUrlAtom = atom(import.meta.env.VITE_API_URL)
const isDevelopmentAtom = atom(import.meta.env.DEV)

Code Splitting

Vite automatically code splits. Leverage this with Jotai:
// Lazy load atoms
const heavyFeatureAtom = atom(async () => {
  const module = await import('./heavy-feature')
  return module.default
})

DevTools

Use Redux DevTools with Jotai in Vite:
import { useAtomsDevtools } from 'jotai-devtools'
import { Provider } from 'jotai'

function App() {
  return (
    <Provider>
      <DevTools />
      <YourApp />
    </Provider>
  )
}

function DevTools() {
  useAtomsDevtools('demo')
  return null
}

Tips

Use the Babel plugins for the best development experience. They add debug labels and enable Fast Refresh for atoms.
Vite’s fast HMR combined with Jotai’s react-refresh plugin means your atom state persists across hot updates.
The jotai-babel plugins work in development and production. Debug labels can help debug production issues.

Build docs developers (and LLMs) love