Persisting State in React Native: Why MMKV + Zustand is the Winning Combo π
If you're building React Native apps, you've probably faced the classic problem: how do I save user data (theme, auth token, cart, preferences) so it survives app restarts?
React Native gives us a few options for local storage, but not all are created equal. Let's walk through the landscape, why persistence matters, the limitations of the old standard, and why MMKV has become the go-to choice β especially when paired with Zustand.
Why Do We Need Persistent State in React Native?
Mobile users expect apps to "remember" them:
- Login tokens should stay valid
- Shopping carts shouldn't empty on app close
- Theme preferences (dark/light) should persist
- Onboarding flow shouldn't replay every time
Without persistence, your app feels broken. With good persistence, it feels native and polished.
The Old King: AsyncStorage
For years, AsyncStorage was the default solution. It's simple, works everywhere, and integrates nicely with libraries like Zustand/Redux.
But it has serious downsides:
- Slow: Fully JavaScript-based, serialized bridge calls
- Async-only: Every read/write blocks UI if not careful
- No encryption out of the box
- Deprecated by React Native core team (replaced by community forks)
Benchmarks show MMKV can be 30β100x faster than AsyncStorage in real-world scenarios.
Enter MMKV: The Modern Champion
MMKV (Mobile Key-Value) is a high-performance key-value store developed by Tencent and now maintained by Marc Rousavy (@mrousavy).
Key advantages:
- Written in C++ with JSI bindings β blazing fast
- Synchronous reads/writes (no await needed for get)
- Built-in encryption support
- Multi-process mode (safe for app groups/extensions)
- Tiny footprint, Expo-compatible
- Actively maintained and used in production by big apps
In short: MMKV is what AsyncStorage should have been in 2025.
Zustand + Persistence = Magic
Zustand is the most popular lightweight state manager in React Native today. Its persist middleware makes saving state trivial β if you have a good storage backend.
That's where most people hit friction: wiring MMKV manually is verbose, error-prone, and doesn't handle instance sharing or encryption cleanly.
Introducing zustand-mmkv-storage
I built zustand-mmkv-storage to solve exactly this.
It's a tiny (<1KB), zero-dependency adapter that lets you use MMKV as the storage backend for Zustand's persist β with all the modern features you'd expect:
- Lazy dynamic import β no startup cost
- Global instance caching β same config = same MMKV instance (efficient & consistent)
- Full encryption support
- Multiple isolated stores (perfect for separating auth, settings, user data)
- Hydration-ready (no flash of empty state)
- Works with Expo & bare React Native
Installation
npm install zustand-mmkv-storage zustand react-native-mmkv
# or
yarn add zustand-mmkv-storage zustand react-native-mmkv
# or
pnpm add zustand-mmkv-storage zustand react-native-mmkv
Simple Usage
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import { mmkvStorage } from 'zustand-mmkv-storage';
export const useBearStore = create(
persist(
(set) => ({
bears: 0,
addBear: () => set((state) => ({ bears: state.bears + 1 })),
}),
{
name: 'bear-storage', // key in MMKV
storage: createJSONStorage(() => mmkvStorage),
}
)
);
That's it. Your bears count now persists across app restarts β fast and reliably.
Advanced: Encrypted & Isolated Storage
import { createMMKVStorage } from 'zustand-mmkv-storage';
const secureStorage = createMMKVStorage({
id: 'secure-vault', // separate file
encryptionKey: 'my-secret-2025', // enables encryption
});
export const useAuthStore = create(
persist(
(set) => ({
token: '',
setToken: (token) => set({ token }),
}),
{
name: 'auth-storage',
storage: createJSONStorage(() => secureStorage),
}
)
);
Now your auth token is encrypted on disk and completely isolated from other data.
Use Cases
Auth tokens & refresh tokens
User preferences (theme, language)
Shopping carts / offline forms
Onboarding completion
Feature flags / A-B testing
Try It Today!
npm i zustand-mmkv-storage
If this saves you time or makes your app faster, I'd love a β on GitHub!
Thanks for reading β happy (and fast) persisting! π»β¨
Top comments (0)