Frequently Asked Questions¶
General¶
How do I store objects, arrays or other non-string values?¶
AsyncStorage only stores strings. Serialize values with JSON.stringify before writing, and JSON.parse when reading:
import { createAsyncStorage } from "@react-native-async-storage/async-storage";
const storage = createAsyncStorage("my-app");
// Storing an object
const user = { name: "John", age: 30 };
await storage.setItem("user", JSON.stringify(user));
// Reading it back
const raw = await storage.getItem("user");
const user = raw ? JSON.parse(raw) : null;
Is there a way to use the old v2-style singleton?¶
Yes. The default export is a backward-compatible v2 instance:
import AsyncStorage from "@react-native-async-storage/async-storage";
await AsyncStorage.getItem("key");
This uses the same legacy API as v2, including multiGet, multiSet, etc. If you are starting a new integration,
prefer createAsyncStorage instead. See the Migration guide for the full API comparison.
Integrations¶
Redux Persist¶
The v3 AsyncStorage instance implements exactly the storage interface Redux Persist expects (getItem, setItem,
removeItem), so you can pass an instance directly as the storage option:
import { createAsyncStorage } from "@react-native-async-storage/async-storage";
import { persistReducer, persistStore } from "redux-persist";
import { combineReducers, createStore } from "redux";
const storage = createAsyncStorage("redux");
const persistConfig = {
key: "root",
storage,
};
const rootReducer = combineReducers({
// your reducers
});
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = createStore(persistedReducer);
const persistor = persistStore(store);
Use default export for migration from v2
The default export (import AsyncStorage from "...") implements the same interface and can be passed as storage too.
It allows for gradual migration to v3.
TanStack Query¶
TanStack Query's @tanstack/query-async-storage-persister package expects a storage object with getItem, setItem,
and removeItem. The v3 AsyncStorage instance matches this interface directly:
import { createAsyncStorage } from "@react-native-async-storage/async-storage";
import { createAsyncStoragePersister } from "@tanstack/query-async-storage-persister";
import { QueryClient } from "@tanstack/react-query";
import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client";
const queryClient = new QueryClient({
defaultOptions: {
queries: {
gcTime: 1000 * 60 * 60 * 24, // 24 hours
},
},
});
const storage = createAsyncStorage("tanstack-query");
const persister = createAsyncStoragePersister({ storage });
export default function App() {
return (
<PersistQueryClientProvider
client={queryClient}
persistOptions={{ persister }}
>
<YourApp />
</PersistQueryClientProvider>
);
}
Required packages
Install @tanstack/query-async-storage-persister and @tanstack/react-query-persist-client separately.
Zustand¶
Zustand's persist middleware accepts a custom storage adapter via createJSONStorage. Pass a factory function
returning an AsyncStorage instance:
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";
import { createAsyncStorage } from "@react-native-async-storage/async-storage";
const storage = createAsyncStorage("zustand");
interface BearState {
bears: number;
addBear: () => void;
reset: () => void;
}
export const useBearStore = create<BearState>()(
persist(
(set) => ({
bears: 0,
addBear: () => set((state) => ({ bears: state.bears + 1 })),
reset: () => set({ bears: 0 }),
}),
{
name: "bear-storage",
storage: createJSONStorage(() => storage),
}
)
);
createJSONStorage handles serialization, so you don't need to manually call JSON.stringify / JSON.parse.
Error handling¶
How do I handle errors from AsyncStorage?¶
All AsyncStorage methods throw AsyncStorageError on failure. Use a try/catch block and inspect e.type to handle
specific failure modes:
import {
AsyncStorageError,
createAsyncStorage,
} from "@react-native-async-storage/async-storage";
const storage = createAsyncStorage("my-app");
try {
await storage.setItem("key", "value");
} catch (e) {
if (e instanceof AsyncStorageError) {
console.error(`Storage error [${e.type}]: ${e.message}`);
}
}
See the Error handling guide for the full list of error types and what each one means.
What happens if a batch operation partially fails?¶
Batch operations (setMany, getMany, removeMany) are atomic. If any part of the operation fails, the entire batch
is rolled back and an AsyncStorageError is thrown. No partial writes will be committed.