The New Default. Your hub for building smart, fast, and sustainable AI software
Table of Contents
React Native Async Storage is a simple, asynchronous key-value storage system for persisting small amounts of data on mobile devices. It allows apps to save and retrieve information like user preferences, app settings, or cached data - even after the app has been closed or restarted. Originally bundled with React Native, it is now maintained as a community package.
For developers building cross-platform mobile apps, reliable data persistence is essential for a seamless user experience. Async Storage addresses this need with a lightweight, non-blocking API that works across iOS and Android.
TL;DR:
Async Storage is a lightweight key-value store for React Native that persists simple data like user preferences and flags across app sessions. It stores data as unencrypted strings with a 6 MB default limit. For sensitive data, use expo-secure-store or react-native-keychain. For complex or large datasets, use SQLite or Realm.
When building mobile apps, one key aspect that developers must consider is how to make their apps remember data. Even after the app has been closed or restarted, this capability ensures a seamless user experience and ongoing data management. React Native, a popular framework for cross-platform app development, addresses this need by providing community-maintained packaged Async Storage. React Native Async Storage stands out as an effective and lightweight tool for handling simple key-value data pairs. This blog post explores what React Native Async Storage is and provides a step-by-step guide on how to implement it and use it efficiently in projects.
Understanding React Native Async Storage
Async Storage is a simple yet powerful key-value storage system in React Native. You can think of it as an asynchronous, mobile counterpart of web Local Storage. It allows the app to save and retrieve small amounts of data like user preferences, simple app settings, or cached data for offline functionality. In older React Native versions, it came included in projects by default, but now it is a community-maintained package.[^1]
Async Storage's straightforward API makes it accessible to developers, providing essential functions such as storing, retrieving, deleting, and clearing all data to easily manage information. This simplicity is balanced by its non-blocking, asynchronous nature, which ensures that data operations do not interfere with the main thread or app performance. Although primarily suited for storing lightweight data, Async Storage can also store more complex data structures, such as JSON objects. Leveraging Async Storage, React Native developers can create apps with improved offline capabilities and a more seamless user experience, ensuring that important data is retained between sessions.
How Does React Native Async Storage Work?
Async Storage is persistent storage, meaning data saved there is stored on the device’s physical memory and remains available across app launches. This makes it a perfect solution for storing data that should be kept, regardless of whether the React mobile app is active, inactive, or not running at all.
Key-Value Pair Storage
Async Storage operates on a simple key-value pair storage system, similar to JavaScript’s localStorage but with added capabilities for mobile environments. Each piece of data is linked to a unique key, a string used as an identifier to store, retrieve, or delete the data. The value is also stored as a string, meaning developers should serialize more complex data structures like arrays or objects using JSON.stringify() and parse them back with JSON.parse() upon retrieval. This approach allows for flexibility in data storage while maintaining simplicity. For instance, an app can store a user's preferred language as a key-value pair such as (preferredLanguage, English), enabling it to quickly access and apply the setting when the app is reopened.
Data Persistence
Another main feature of Async Storage is its ability to persist data, meaning that data stored remains available even after the app is closed or the device is restarted. Stored locally on the device's file system and separate from the app's volatile memory - cleared when the app restarts - Async Storage ensures that user preferences, small caches, or other important non-volatile data stay consistent across sessions. This feature is essential for user experience; for example, storing a user's onboarding status enables an app to remember whether the user has completed the initial walkthrough or tutorial.
Asynchronous Operations
Async Storage functions asynchronously, not blocking the app's main thread while reading or writing data. This is essential for app performance and responsiveness, especially on devices with limited resources. Because the operations are asynchronous, React Native developers interact with Async Storage using Promises or async/await syntax. This helps keep the app's UI smooth and fluid, as data operations do not cause delays or freezing.
Where Is Data Stored on the Device?
Definitely not inside the application. On iOS, there are two possible locations where data saved to Async Storage can be stored. If data does not exceed 1024 characters, it is stored in a common manifest.json file; if it is bigger, it is stored in individual, dedicated files.[^2]
On Android, all the data stored in Async Storage is saved in the phone's SQLite database.
There are also some restrictions on how much data and big entries can be kept in Async Storage. This is mainly because of some limitations in SQLite's storage capacity. The default limit is 6 MB for the total amount of data and 2 MB per record. The Async Storage library allows users to adjust the total storage size by setting an AsyncStorage_db_size_in_MB flag.[^3] However, it is important to keep in mind that the available space on the device's memory should not be exceeded when testing the limit
React Native Async Storage: Use Cases, Limitations, and Security Considerations
Before choosing Async Storage for your project, it helps to understand where it works well, where it doesn't, and what security trade-offs to account for.
Where Async Storage Works Best
Async Storage works best for lightweight, non-sensitive data that should persist between sessions. Typical use cases include:
Storing user preferences (language, theme, notification settings)
Caching onboarding or tutorial completion status
Persisting simple app state (last viewed screen, selected filters)
Supporting offline mode - libraries like TanStack Query use Async Storage to cache query results for offline access[^4]
Storing non-sensitive feature flags or configuration values
What Async Storage Cannot Do
Async Storage is not a general-purpose database. Its constraints are important to understand before choosing it:
String-only storage - all values must be strings. Objects and arrays require JSON.stringify() / JSON.parse(), which adds overhead and has no built-in schema validation.
Size limits - the default total storage cap is 6 MB, with a 2 MB limit per individual record. These can be adjusted on Android via the AsyncStorage_db_size_in_MB flag, but pushing against device storage limits is not recommended.
No querying or indexing - data can only be retrieved by its exact key. There is no way to search, filter, or run queries across stored data.
No encryption - data is stored in plaintext on the device's file system. Any data stored in Async Storage should be considered readable.
Not suited for relational or complex data - for structured datasets, relationships, or anything requiring queries, use SQLite or Realm instead.
Feature | Async Storage | SQLite | Realm | expo-secure-store |
Data model | Key-value (strings) | Relational (SQL) | Object-oriented | Key-value (strings) |
Best for | Preferences, flags, small cache | Structured data, queries | Complex objects, offline-first | Tokens, secrets, credentials |
Storage limit | 6 MB default | Device storage | Device storage | ~2 KB per item (iOS) |
Encryption | No | Optional (SQLCipher) | Optional (encrypted Realm) | Yes (native keystore) |
Querying | By key only | Full SQL | Object queries | By key only |
Setup Complexity | Minimal | Moderate | Moderate | Minimal |
Why Async Storage Is Not Safe for Sensitive Data
Async Storage is unencrypted. Even though each app has its own sandboxed storage, storing sensitive information like authentication tokens, API keys, or personal data in Async Storage is not safe.[^5]
On rooted or jailbroken devices, sandboxing can be bypassed, exposing anything stored in plaintext. Login tokens, session data, and secrets should never be placed in Async Storage - see the "Secure Storage in React Native" section below for the right alternatives.
Setting Up React Native Async Storage: Step-by-Step Guide
Follow this Async Storage React Native tutorial to set up the tool smoothly and use it in your React Native app or Expo project. The process is straightforward.
Let's start by installing the library. Run the following command in your project directory (you can also add it to your Expo project):
npm install @react-native-async-storage/async-storageImporting Async Storage:
import AsyncStorage from '@react-native-async-storage/async-storage';When using the library, there is one important thing to remember - Async Storage can only store string data. So, if you need to store a JSON object, remember to serialize it first.
How to Use Async Storage in React Native
The API is simple. Below are three functions that cover the most common operations: saving, retrieving, and removing data. One thing to remember: Async Storage can only store string data, so if you need to store a JSON object, serialize it first.
Saving data to Async Storage
async function saveDataToAsyncStorage(key: string, data: SomeData) {
try {
if (data) {
await AsyncStorage.setItem(key, JSON.stringify(data));
}
} catch (error) { // handle error }
}
Getting data from Async Storage
async function getDataFromAsyncStorage(key: string) {
try {
const data = await AsyncStorage.getItem(key);
// if your data was an json object remember to parse it
if (data) { return JSON.parse(data); }
} catch (error) { // handle error }
}
Removing data from Async Storage
async function clearAsyncStorage(key: string) {
try {
await AsyncStorage.removeItem(key);
} catch (error) { // handle error }
}
By following these steps, you can effectively implement and manage data storage in your React Native app. However, if the functions presented are insufficient for your use case, Async Storage has great documentation on their API.
There is also an ongoing discussion about Async Storage hook implementation on Github that is worth checking out if you’d like to dive deeper into the subject.
Secure storage in React Native
As mentioned earlier in the article, sensitive information, such as user tokens, should not be stored in Async Storage. So, where should it be stored? The short answer is in one of the dedicated React Native libraries. There are several options, such as expo-secure-store or react-native-keychain.
While their APIs look almost identical to Async Storage API, it's good to know they are different under the hood. These libraries keep the data in a dedicated, encrypted place specifically designed for sensitive information. This ensures that the data is securely stored within the system and prevents other apps on the device from accessing it. On iOS, data saved in the secure storage is kept in Keychain Services and Secured Shared Preferences on Android.[^6]
Best Practices for Using Async Storage in React Native
Keep stored data small and simple
Async Storage is designed for lightweight key-value pairs, not large datasets. Store user preferences, flags, and small cached values. If you find yourself storing hundreds of keys or megabytes of data, that is a signal to migrate to SQLite or Realm. Staying within the 6 MB default limit is not just a technical constraint - it is a design principle.
Use secure alternatives for sensitive data
Never store authentication tokens, API keys, passwords, or personal health/financial data in Async Storage. Use expo-secure-store for Expo projects or react-native-keychain for bare React Native projects. These libraries encrypt data at rest using the platform's native secure storage (iOS Keychain, Android Keystore).
Structure data with JSON consistently
Since Async Storage only accepts strings, adopt a consistent pattern for serializing and deserializing complex data. Always wrap storage operations with JSON.stringify() and JSON.parse(), and validate the parsed output. A corrupted or unexpected value can crash your app if you parse it without checking.
Handle errors on every operation
Every Async Storage call can fail - the device may be out of storage, the key may not exist, or the data may be corrupted. Always wrap operations in try/catch blocks. Silent failures in storage operations lead to bugs that are difficult to reproduce and diagnose, especially across different devices and OS versions.
Use multiGet and multiSet for batch operations
When reading or writing multiple keys at once, use multiGet and multiSet instead of calling getItem and setItem in a loop. Batch operations are more performant and reduce the number of bridge crossings between JavaScript and native code, which matters on lower-end devices.
When to Use React Native Async Storage - and When Not To
Async Storage solves a specific problem well: persisting small, non-sensitive key-value data across app sessions with minimal setup. For user preferences, feature flags, onboarding state, and lightweight caching, it remains the standard choice in the React Native ecosystem.
Where it falls short is equally important to understand. It offers no encryption, no querying, no indexing, and a relatively low storage ceiling. Using it beyond its intended scope - storing tokens, caching large datasets, or managing relational data - does not just underperform; it introduces real security and reliability risks.
The right approach is to treat Async Storage as one tool in a broader data management strategy: Async Storage for simple persistence, a secure storage library for credentials and secrets, and SQLite or Realm for structured or large-scale data. Knowing where each fits is what separates a functional app from a well-architected one.
Key Takeaways
Async Storage is a persistent, asynchronous key-value store - the mobile equivalent of localStorage, maintained as a community package since being removed from React Native core.
It is best suited for lightweight data - user preferences, feature flags, onboarding state, and small caches. The default storage limit is 6 MB total, 2 MB per record.
It is not secure - all data is stored unencrypted in plaintext. Never use it for tokens, passwords, API keys, or any sensitive information.
Use secure alternatives for credentials - expo-secure-store (Expo) or react-native-keychain (bare RN) encrypt data using native platform keystores.
For complex or large data, use a proper database - SQLite or Realm provide querying, indexing, and higher storage capacity that Async Storage cannot match.
Bibliography:
[^1]: https://github.com/react-native-async-storage/async-storage
[^2] https://react-native-async-storage.github.io/async-storage/docs/advanced/where_data_stored
[^3] https://react-native-async-storage.github.io/async-storage/docs/limits
[^4] https://tanstack.com/query/latest/docs/framework/react/plugins/createAsyncStoragePersister
React Native Async Storage FAQ
)




