This episode looks at Zustand v5 as the stable version: the useStore function compatible with React 19 and the use hook, middleware typing improvements, and the 2026 release series from v5.0.10 to v5.0.14 that brought fixes for the persist race condition and devtools. You also learn to verify the latest version in the registry.

Nearing the end of the series, we look at Zustand v5 as the stable version that serves as the production foundation. Episode 20 covers the capabilities that arrived with v5: the useStore function compatible with React 19 and the use hook, middleware typing improvements, and the 2026 release series from v5.0.10 to v5.0.14 that brought fixes for the persist race condition and devtools improvements.
You'll also learn how to verify the latest version in the registry before bumping dependencies in your project.
Zustand v5 adds a useStore function to the main package, separate from the useStore hook produced by create. This allows using a vanilla store with React 19's use hook directly:
import { use } from 'react'
import { useStore } from 'zustand'
import { counterStore } from './counter-store'
export function useCounterReadonly() {
return useStore(counterStore, (s) => s.count)
}
export function CounterValue() {
const count = use(useCounterReadonly())
return <span>{count}</span>
}use(useCounterReadonly()) combines useStore with the use hook, following the resource pattern introduced in React 19. Zustand v5 still supports the old way — the regular hook from create — so migration doesn't force a big change.
v5 cleans up the exports: useShallow is now imported from zustand/react/shallow, and createStore is available from zustand/vanilla. We already used both in episodes 13 and 17:
import { useShallow } from 'zustand/react/shallow'
import { createStore } from 'zustand/vanilla'
import { useStore } from 'zustand'createStore from zustand/vanilla and useStore from zustand become the pair for bringing a vanilla store into React, while useShallow simplifies multi-selectors without additional dependencies.
The previous version 4 often forced create calls with double parentheses when using middleware. v5 improves type inference so more cases can be written without double parentheses:
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
interface CartState {
items: string[]
addItem: (id: string) => void
}
export const useCart = create<CartState>()(
persist(
(set) => ({
items: [],
addItem: (id) => set((s) => ({ items: [...s.items, id] })),
}),
{ name: 'cart' },
),
)create<CartState>()(persist(...)) remains the safest form for full typing. What changed in v5: middleware rarely obscures the state type anymore, and middleware composition like devtools(persist(...)) produces more accurate types.
From January to May 2026, the team released v5.0.10 through v5.0.14 with fixes relevant to production:
The pattern used: patch versions are still backported to v4 when needed, while feature development continues on v5. Always read the changelog in the repo before upgrading.
Before bumping a dependency, check the latest version in the registry:
npm view zustand versionnpm view zustand version shows the latest stable version. To see the list of recent patch releases:
npm view zustand versions --jsonBy checking the registry before upgrading, you know whether the fix you need is already available in the latest version or still waiting for the next release.
Episode 20 summarizes Zustand v5 as the stable version: useStore for React 19, cleaned-up exports for useShallow and createStore, better middleware typing, and the 2026 release series that fixed the persist race condition and devtools.
Key takeaways:
In the next episode we will discuss production-ready architecture — store folder structure in a team, slices patterns per feature, action naming conventions, per-domain code-splitting, and integrating linting, type-checking, test coverage, and documentation for onboarding.