Skip to main content
The createStore function creates a vanilla Zustand store that can be used outside of React or with any UI framework. It returns a store API object instead of a React Hook.

Import

import { createStore } from 'zustand/vanilla'

Type Signature

function createStore<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
  initializer: StateCreator<T, [], Mos>
): Mutate<StoreApi<T>, Mos>

// Curried version
function createStore<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(
  initializer: StateCreator<T, [], Mos>
) => Mutate<StoreApi<T>, Mos>

Parameters

initializer
StateCreator<T, [], Mos>
required
A function that receives set, get, and store as arguments and returns the initial state object with actions.The function signature is:
(set: SetState<T>, get: GetState<T>, store: StoreApi<T>) => T
  • set: Function to update the state
  • get: Function to get the current state
  • store: The store API object

Returns

store
StoreApi<T>
A store API object with the following methods:

Basic Usage

import { createStore } from 'zustand/vanilla'

interface BearState {
  bears: number
  increase: () => void
  decrease: () => void
}

const bearStore = createStore<BearState>()((set) => ({
  bears: 0,
  increase: () => set((state) => ({ bears: state.bears + 1 })),
  decrease: () => set((state) => ({ bears: state.bears - 1 })),
}))

// Get state
const currentBears = bearStore.getState().bears

// Update state
bearStore.getState().increase()

// Subscribe to changes
const unsubscribe = bearStore.subscribe((state, prevState) => {
  console.log('Bears:', state.bears)
})

Using with React

You can use a vanilla store with React by importing useStore from zustand:
import { createStore } from 'zustand/vanilla'
import { useStore } from 'zustand'

const bearStore = createStore<BearState>()((set) => ({
  bears: 0,
  increase: () => set((state) => ({ bears: state.bears + 1 })),
}))

function BearCounter() {
  const bears = useStore(bearStore, (state) => state.bears)
  return <h1>{bears} around here...</h1>
}

function Controls() {
  const increase = useStore(bearStore, (state) => state.increase)
  return <button onClick={increase}>Add bear</button>
}

Direct State Updates

You can update state directly using setState:
// Partial update (shallow merge)
bearStore.setState({ bears: 10 })

// Function update
bearStore.setState((state) => ({ bears: state.bears + 1 }))

// Replace entire state
bearStore.setState({ bears: 0 }, true)

Vanilla JavaScript Example

Here’s a complete vanilla JavaScript example:
import { createStore } from 'zustand/vanilla'

type PositionStore = {
  position: { x: number; y: number }
  setPosition: (position: { x: number; y: number }) => void
}

const positionStore = createStore<PositionStore>()((set) => ({
  position: { x: 0, y: 0 },
  setPosition: (position) => set({ position }),
}))

const dot = document.getElementById('dot')
const container = document.getElementById('container')

container.addEventListener('pointermove', (e) => {
  positionStore.getState().setPosition({
    x: e.clientX,
    y: e.clientY,
  })
})

positionStore.subscribe((state) => {
  dot.style.transform = `translate(${state.position.x}px, ${state.position.y}px)`
})

Use Cases

Framework Agnostic

Use Zustand with Vue, Svelte, Angular, or vanilla JavaScript

Server-Side

Create stores in Node.js environments without React dependencies

Testing

Easier to test stores in isolation without React Testing Library

Shared State

Share state between React and non-React parts of your application
Vanilla stores are the foundation of Zustand. The create function from the main package actually uses createStore internally and wraps it with a React Hook.
  • create - Create a React Hook-based store
  • useStore - Use a vanilla store in React components

Build docs developers (and LLMs) love