mrkeyoor.com_
Tue 22 Sept 22:36 UTC
npmMobileupdated 22 Sept 2026

@react-native-async-storage/async-storage review

Async Storage is persistent, unencrypted string storage for React Native, with SQLite backends on Android, iOS, and macOS, IndexedDB on web, and a single legacy store on Windows and visionOS. Version 3 replaces the singleton-first design with named storage instances and renames the batch API; 3.1.1 updates the native SQLite and Room dependencies. Our install was much heavier than its small JavaScript bundle because npm pulled a React Native dependency graph and the package itself includes native platform code. Use it for preferences and replaceable cached state, never for credentials.

Verdict

Async Storage 3.1.1 is a sound place for non-secret React Native preferences and cache state when scoped stores help. Its major-version migration, native setup, 221 MB clean install, and 7 high audit findings all deserve review before an upgrade.

We installed it

Lab card: what happened when we installed @react-native-async-storage/async-storageScreenshot of @react-native-async-storage/async-storage documentation
Install✓ · 14.5s208 packages on disk · 221 MB
ImportESM import fails · require() fails · CommonJS package with exports map
Browser2.6 KBgzipped (7.7 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns70 critical · 7 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does @react-native-async-storage/async-storage install cleanly?

Yes. In a fresh container with an empty cache, npm install @react-native-async-storage/async-storage finished in 15 seconds, leaving 208 packages and 221 MB on disk. npm audit reported 7 known vulnerabilities.

How much does @react-native-async-storage/async-storage add to a browser bundle?

2.6 KB gzipped (7.7 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does @react-native-async-storage/async-storage work with both ESM and CommonJS?

Neither plain import nor require succeeded in our sandbox, so it needs a bundler or extra setup.

Does @react-native-async-storage/async-storage include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

@react-native-async-storage/async-storage or react-native-mmkv: which should you use?

react-native-mmkv: Use it when synchronous reads and a faster native key-value engine matter more than Async Storage's IndexedDB path. Async Storage 3.1.1 is a sound place for non-secret React Native preferences and cache state when scoped stores help.

When should you not use @react-native-async-storage/async-storage?

The values include passwords, refresh tokens, private keys, or regulated records. The project describes its storage as unencrypted; use Keychain, Keystore, or a secure-store wrapper.

API stability3/5Version 3 changes the central usage model from a singleton to named instances, drops callback arguments and merge behavior, removes `useAsyncStorage`, and replaces multiGet, multiSet, and multiRemove with methods that also use different data shapes. The default export still reaches legacy data so migration can be gradual. Core single-key methods retain familiar signatures, but an established version 2 codebase will need deliberate caller and data migration work.
Docs5/5The official site documents current platform floors, each database-name mapping, string-only values, atomic batch calls, categorized errors, the version 2 compatibility export, and the exact version 3 method changes. Its Jest page supplies both the transform rule and shipped in-memory mock. Installation guidance is clear for CocoaPods; teams still need React Native or Expo build knowledge to diagnose native linking and dependency audit results outside this package's pages.
Maintenance5/5GitHub shows an unarchived repository with 5,073 stars, a push on August 23, 2026, and 23 open issues and pull requests in the combined counter. Release 3.1.1 shipped on May 29, 2026 to update native SQLite and Room dependencies, after 3.1.0 moved the shared Android artifact to Maven Central. Recent fixes also cover Apple error mapping, Android concurrency, initialization locking, and a missing Jest build artifact.
Ecosystem5/5The npm downloads endpoint counted 6,971,108 downloads for August 17 through August 23, 2026. The package targets Android, iOS, macOS, visionOS, web, and Windows, publishes TypeScript declarations, and includes a Jest implementation. React and React Native are peer dependencies, which keeps framework ownership with the app but made our isolated npm install expand to 208 packages and 221 MB. Secure data and queryable records still require different tools.

Use it if

  • A React Native app needs durable strings for settings, onboarding state, drafts, or JSON cache entries across launches.
  • Separate named stores should isolate user data, cache data, or feature state on Android, iOS, macOS, and web.
  • Several keys must be written or removed atomically through the version 3 `setMany` and `removeMany` calls.
  • Your supported devices meet the version 3 floors, including React Native 0.76 for iOS and Android and Android API 24.
Skip it if

Setup reality

We installed version 3.1.1 in a fresh Node 22 Bookworm container. npm completed in 14.5 seconds, left 208 packages, and used 221 MB on disk. The package has 1 direct dependency, 2 peer dependencies, and 51,316 KB unpacked. npm audit reported 7 known vulnerabilities, all high severity. TypeScript declarations ship in the package. Its measured browser bundle was 7.7 KB minified and 2.6 KB gzipped.

The package has a CommonJS package boundary and an exports map, yet both require() and ESM import failed in our plain Node check under Node.js v22.23.2. That environment has no React Native native module, so validate it inside the actual app toolchain. npm installed the peer graph in our sandbox; your project must provide compatible React and React Native versions. Run pod install for iOS or macOS native projects.

Version 3 code starts with createAsyncStorage('name'). Android, iOS, and macOS turn that name into a SQLite path; web uses it as the IndexedDB database name. Do not include a file extension. Windows and visionOS use one legacy store. The default export also points to legacy version 2 data for migration, while new scoped stores start separately. Plan how old keys move before changing every import.

Values must be strings, so JSON parsing, data-version migration, and corrupt-value handling remain application work. Jest needs the package's in-memory /jest implementation and an ESM transform exception; clear all mock stores between tests. Storage methods can reject with categorized native-module, web, SQLite, other-storage, or unknown errors. Review the 7 high audit findings against the lockfile before shipping, and keep secret material in protected platform storage.

Patterns

Open two isolated stores create-scoped-storage

import {createAsyncStorage} from '@react-native-async-storage/async-storage';

export const userStore = createAsyncStorage('user');
export const cacheStore = createAsyncStorage('cache');

Scoped stores work on Android, iOS, macOS, and web. Windows and visionOS fall back to one legacy store.

Save and read one string store-string

await userStore.setItem('theme', 'dark');

const theme = await userStore.getItem('theme');
if (theme === null) {
  applyDefaultTheme();
}

A missing key returns null. An empty string is a stored value, so do not use a truthiness check.

Persist JSON with a schema version store-versioned-json

const record = {version: 2, theme: 'dark', fontScale: 1.1};
await userStore.setItem('preferences', JSON.stringify(record));

const raw = await userStore.getItem('preferences');
const saved = raw === null ? null : JSON.parse(raw);

Async Storage accepts strings only. Validate the parsed object and migrate older versions before use.

Delete one optional value remove-item

await userStore.removeItem('draft');

Removing a missing key resolves without an error. Do not use this store for authentication secrets.

Write several keys atomically write-atomic-batch

await userStore.setMany({
  theme: 'dark',
  locale: 'en-GB',
  onboardingComplete: 'true',
});

Version 3 accepts a record in `setMany`; the older `multiSet` tuple-array shape does not apply.

Fetch several keys in one call read-batch

const values = await userStore.getMany(['theme', 'locale', 'draft']);
console.log(values.theme, values.locale);
if (values.draft === null) {
  createEmptyDraft();
}

getMany returns a record containing every requested key and null for each missing value.

Remove a group of keys atomically remove-atomic-batch

await cacheStore.removeMany([
  'feed',
  'feedFetchedAt',
  'feedEtag',
]);

The version 3 name is `removeMany`. Missing keys are ignored.

Inspect keys inside one scope list-store-keys

const keys = await userStore.getAllKeys();
for (const key of keys) {
  console.log(key);
}

Named storage limits this list to the selected scope on platforms that support multiple stores.

Clear a cache store clear-one-scope

const keysBefore = await cacheStore.getAllKeys();
await cacheStore.clear();
console.log(`removed ${keysBefore.length} cache entries`);

clear is destructive within that store. Keep user-owned settings and replaceable cache data in different scopes.

Move a key from the legacy singleton migrate-legacy-data

import LegacyStorage, {createAsyncStorage} from '@react-native-async-storage/async-storage';

const current = createAsyncStorage('user');
const oldTheme = await LegacyStorage.getItem('theme');
if (oldTheme !== null) {
  await current.setItem('theme', oldTheme);
  await LegacyStorage.removeItem('theme');
}

Write the new store before deleting the legacy value so an interrupted migration can retry safely.

Branch on the documented error type classify-storage-error

import {AsyncStorageError} from '@react-native-async-storage/async-storage';

try {
  await userStore.setItem('theme', 'dark');
} catch (error) {
  if (error instanceof AsyncStorageError) {
    reportStorageFailure(error.type, error.message);
  } else {
    throw error;
  }
}

The type distinguishes native-module, web, SQLite, other-storage, and unknown failures. Do not turn every write failure into a cache miss.

Load and reset the Jest store mock-storage-in-jest

jest.mock('@react-native-async-storage/async-storage', () =>
  require('@react-native-async-storage/async-storage/jest')
);

const {clearAllMockStorages} = require('@react-native-async-storage/async-storage/jest');
afterEach(() => clearAllMockStorages());

Jest may also need this package allowed through `transformIgnorePatterns` because the published source path uses ESM.

Alternatives

PackageRegistryPick it when
react-native-mmkvnpmUse it when synchronous reads and a faster native key-value engine matter more than Async Storage's IndexedDB path.
expo-secure-storenpmUse it in Expo apps for small secrets that need platform-protected storage rather than an unencrypted database.
react-native-keychainnpmUse it for credentials that need Keychain or Keystore access controls and optional biometric policies.

More mobile guides

react-native · react-native-safe-area-context · expo · react-native-reanimated · react-native-svg · react-native-worklets · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.