react-native-encrypted-storage is a React Native library that stores small pieces of sensitive data securely by wrapping iOS Keychain Services and Android's EncryptedSharedPreferences, giving you a drop-in, encrypted alternative to the plaintext AsyncStorage. If your app holds auth tokens, refresh tokens, or any secret on the device, AsyncStorage is the wrong place for them, and react-native-encrypted-storage is one of the common answers. This guide explains what it does, how to use it safely, its maintenance situation, and how it stacks up against react-native-secure-storage.
The problem it solves
React Native's community AsyncStorage is unencrypted key-value storage. On Android it is a plaintext file; on iOS it is an unencrypted store. That is fine for a UI theme preference and dangerous for an access token. On a rooted or jailbroken device, or via a device backup, plaintext storage is trivially readable.
The platforms already provide secure primitives for exactly this: iOS Keychain Services stores small secrets in an OS-managed, hardware-backed store, and Android's EncryptedSharedPreferences (from the Jetpack Security library) transparently encrypts both keys and values. react-native-encrypted-storage, maintained by the developer known as emeraldsanto, is a thin JavaScript wrapper that routes your reads and writes to Keychain on iOS and EncryptedSharedPreferences on Android, with TypeScript support included.
Basic usage
The API mirrors AsyncStorage, which is what makes it an easy swap. Install it:
npm install react-native-encrypted-storage
cd ios && pod install
Then store, retrieve, and remove values:
import EncryptedStorage from "react-native-encrypted-storage";
async function storeToken(token) {
try {
await EncryptedStorage.setItem(
"user_session",
JSON.stringify({ token })
);
} catch (error) {
// handle write failure
}
}
async function getToken() {
const session = await EncryptedStorage.getItem("user_session");
return session ? JSON.parse(session) : null;
}
async function clearToken() {
await EncryptedStorage.removeItem("user_session");
}
Values are strings, so serialize objects with JSON.stringify on the way in. The methods are async and can throw, so wrap them; a missing key returns null rather than throwing.
Use it for the right things
Secure storage is for small secrets, not bulk data. Keychain in particular is designed for short items — tokens, credentials, small keys — not for caching megabytes of API responses. Store the auth token and the refresh token there; keep the large, non-sensitive cache in a regular store or a database.
A few practices that matter more than the library choice:
- Store the minimum. The safest secret is the one you do not persist. If you can keep a token in memory for the session, do that instead of writing it to disk.
- Clear on logout. Call
removeItem(orclear) when the user signs out so a shared device does not leak the previous session. - Do not treat encrypted-at-rest as tamper-proof. On a compromised (rooted/jailbroken) device, a determined attacker with the app running can still reach data the app can reach. Encrypted storage raises the bar significantly; it is not an absolute guarantee.
Maintenance status: read before you commit
Here is the part worth checking before you standardize on it. As of this writing, react-native-encrypted-storage is popular — on the order of tens of thousands of weekly downloads — but its release cadence has slowed, with the last published version roughly a year old and a single maintainer on the project. That is not a reason to panic, but it is a reason to plan.
Two concrete implications:
- New React Native architecture. React Native's move toward the New Architecture (Fabric/TurboModules) means native modules occasionally need updates to stay compatible. A slowly maintained native module can lag a React Native upgrade, so verify compatibility before you bump RN versions.
- Underlying platform libraries. On Android the security depends on the Jetpack Security (
EncryptedSharedPreferences) library, which itself has shifted maintenance status over time. A wrapper is only as current as what it wraps.
Community forks exist — for example, a Tonkeeper fork adjusts Keychain attributes — which is a signal that some teams needed changes upstream had not merged. If you adopt the base package, watch its repository and pin the version in your lockfile so an unexpected change cannot slip in. An SCA tool such as Safeguard can flag when a dependency like this goes stale or picks up a known issue transitively.
How it compares to react-native-secure-storage
People weighing this library often also look at react-native-secure-storage. Be careful: that package is considerably less maintained — its latest version is an early 0.1.x release that has not been updated in roughly seven years, with very low weekly downloads. For most new projects it is not a serious contender; an unmaintained package that touches your secrets is a liability, because a security-sensitive dependency that never gets patched cannot receive a fix when a flaw is found.
Better-supported alternatives to evaluate include react-native-keychain (a mature, widely used option focused specifically on Keychain/Keystore credential storage), rn-secure-storage, and, if you are in the Expo ecosystem, Expo's SecureStore. The right choice depends on whether you are on bare React Native or Expo, how actively the option is maintained at the time you evaluate, and whether you need credential-specific features like biometric-gated access. Evaluate maintenance and download health at the moment you decide, not from a blog snapshot — including this one. For the general discipline of vetting any npm dependency, see our npm security best practices.
Bottom line
react-native-encrypted-storage does a genuinely useful thing: it gives React Native apps an easy, encrypted place to keep small secrets, backed by the platforms' own secure stores. It is the correct instinct to move tokens out of AsyncStorage. Just adopt it with eyes open — check its current maintenance status, pin the version, keep an eye on New Architecture compatibility, and store as little as you can get away with. The library is a tool for reducing risk, not a reason to persist secrets you did not need to persist in the first place.
FAQ
What does react-native-encrypted-storage use under the hood?
On iOS it wraps Keychain Services; on Android it wraps EncryptedSharedPreferences from the Jetpack Security library. Both are OS-provided secure stores, so your secrets are encrypted at rest rather than sitting in plaintext like AsyncStorage.
Is react-native-encrypted-storage still maintained?
It remains popular by download count, but its release cadence has slowed, with the last version roughly a year old and a single maintainer. Pin the version, watch the repository, and verify compatibility before major React Native upgrades. Community forks exist for teams that needed unmerged changes.
How is it different from react-native-secure-storage?
react-native-secure-storage is far less maintained — an early 0.1.x release untouched for around seven years with very low downloads — so it is generally not recommended for new projects. react-native-encrypted-storage, react-native-keychain, and Expo SecureStore are more actively supported options.
Can I store large data in it?
No. Secure stores, especially iOS Keychain, are meant for small secrets like tokens and credentials. Keep bulk, non-sensitive data in a regular store or database and reserve encrypted storage for the sensitive bits.