Skip to content
devcards.space
ReactFrontend

What is Zustand? Simple, Fast and Scalable State Management

Near-zero-boilerplate global state for React with Zustand. Stores, selectors, async actions, persist middleware and full TypeScript support.

7 minute read
Zustand infographic showing store creation, selectors, async actions and persist middleware

Zustand is a small, fast and scalable global state management library for React applications. It needs no provider, ships with far less boilerplate than Redux, and has excellent TypeScript support out of the box. Selectors prevent unnecessary re-renders explicitly; persist middleware lets you write state straight to localStorage. This guide expands the infographic to cover everything from basic usage to advanced patterns.

What is Zustand?

A small, fast and scalable state management library for React. Without reducer/action/dispatch boilerplate, you call a hook and get state plus setters.

  • Less boilerplate
  • Minimal setup
  • Built-in React support
  • Works for both small and large apps

Why Zustand?

What Zustand brings to the table:

  • No provider required
  • Minimal API
  • Built-in TypeScript support
  • Compatible with React Native APIs
  • Much smaller footprint than Redux

Installation

Single package — installed as a runtime dependency.

bash
npm install zustand

Create a Store (Core Idea)

create takes a factory that receives set and returns state and actions. The result is itself a hook.

stores/counter.ts
ts
import { create } from "zustand";

type CounterState = {
  count: number;
  increment: () => void;
  decrement: () => void;
};

export const useCounter = create<CounterState>((set) => ({
  count: 0,
  increment: () => set((s) => ({ count: s.count + 1 })),
  decrement: () => set((s) => ({ count: s.count - 1 })),
}));

Using the Store

The store is a hook. Read values and actions by calling it — no need to wrap your component in anything.

tsx
function Counter() {
  const { count, increment } = useCounter();
  return (
    <button onClick={increment}>
      Count: {count}
    </button>
  );
}

Selectors (IMPORTANT)

Pass a selector to subscribe only to the slice you need. Your component re-renders only when that slice changes — critical for performance.

ts
const count = useCounter((s) => s.count);
const increment = useCounter((s) => s.increment);

Async Actions

Define async functions inside the store and call set as needed. Data fetching, login flows and similar async work fit naturally.

ts
export const useUsers = create((set) => ({
  users: [],
  loading: false,
  fetchUsers: async () => {
    set({ loading: true });
    const res = await fetch("/api/users");
    const users = await res.json();
    set({ users, loading: false });
  },
}));

Persist Middleware

The persist middleware writes the store to localStorage. State survives page reloads. You can also use sessionStorage or a custom storage.

ts
import { create } from "zustand";
import { persist } from "zustand/middleware";

export const useTheme = create(
  persist<{ theme: "light" | "dark"; toggle: () => void }>(
    (set) => ({
      theme: "light",
      toggle: () =>
        set((s) => ({ theme: s.theme === "light" ? "dark" : "light" })),
    }),
    { name: "theme" }
  )
);

Key Concepts

What you'll meet over and over:

  • create — building a store
  • set / get — updating and reading state
  • selectors — subscribing to slices
  • persist — saving state
  • subscriber — listening outside React
  • middleware — devtools, persist, immer, …

Zustand vs Redux

The high-level differences:

  • Zustand: minimal boilerplate, no provider, fast setup
  • Redux: actions/reducers/dispatch, stricter, more setup
  • Zustand keeps growing in modern projects
  • Redux Toolkit reduces classic Redux boilerplate but is still heavier

Use Cases

Where Zustand particularly shines:

  • Global UI state (theme, modal, sidebar)
  • Shared client state
  • Small-to-medium apps
  • React Native apps
  • Form draft / auto-save state

Summary

Zustand is simple, fast and performant. It minimizes boilerplate, offers a great DX and is a fantastic default for modern React apps. The most common modern combo is React Query for server state and Zustand for client state.

Frequently Asked Questions

Common questions about this topic.

Zustand or Redux Toolkit?

For new projects, Zustand is usually enough and brings far less boilerplate. Very large teams or those wanting strict action history and devtools-driven workflows might still prefer Redux Toolkit.

Can I use it for server state?

You can, but it's not recommended. Libraries dedicated to server state — React Query / TanStack Query — handle cache, deduplication and refetch much better. Use Zustand for client state.

Will TypeScript be hard?

No — Zustand's TS support is solid. The create<TState>() generic gives you typed state and actions automatically. You only need careful types when composing middleware.

Can I have multiple stores?

Yes, that's the recommended pattern. Create a store per domain (auth, cart, ui) instead of a single mega-store — easier to test and reason about.

Is there DevTools support?

Yes — the devtools middleware integrates with Redux DevTools, letting you inspect state history and actions during development.

Other infographics on connected topics.

Discover more developer infographics

Visit the homepage so you don't miss new content.

See all infographics