MMKV vs. AsyncStorage: Faster Local Key-Value Storage
AI generated
RN
native
React Native / New Architecture
MMKV vs. AsyncStorage
Faster, synchronous local key-value storage through JSI

AsyncStorage wraps every read and write in an asynchronous bridge call, while MMKV, built on C++ and memory-mapped files, answers synchronously through JSI. This article compares both in speed, API design and encryption, and walks through a practical strategy for migrating existing AsyncStorage data to MMKV.

10 min read MMKV AsyncStorage JSI

1. How AsyncStorage works: asynchronous bridge calls per access

AsyncStorage stores data differently depending on the platform, traditionally in a SQLite database on Android, in a collection of property list files on iOS, and every single access, whether reading or writing, runs through an asynchronous call handled in the past through the classic bridge and today through a TurboModule. Even reading a single small string produces a full asynchronous round trip with promise resolution.

For occasional access, for example saving an auth token once at login, this overhead is unproblematic. But once an app frequently reads or writes many small values, for example form state, UI preferences or feature flags checked on every render, the asynchronous nature of AsyncStorage adds up to noticeable latency and a growing number of concurrent promises.

2. How MMKV works: synchronous, C++-based and backed by mmap

MMKV was originally developed by Tencent for WeChat and is built on a C++ core library that maps data directly into process memory through memory-mapped files, instead of opening, reading or writing a file on every access. Through JSI, MMKV is addressed directly and synchronously from JavaScript, with no promise, bridge serialization or thread switch at all, which makes a fundamental difference for small, frequent accesses.

Since MMKV operates on the same native level operating systems use for efficient file access themselves, the detour through a separate database engine like SQLite disappears entirely. Changes are written incrementally into the underlying file, without every single write having to re-serialize the entire file.

3. Benchmark comparison: read and write times for small values

In publicly available benchmarks, including those published by the MMKV library itself, small values like individual strings or numbers show a speed difference in the range of roughly ten to thirty times in favor of MMKV over AsyncStorage, especially for many consecutive individual accesses. The difference grows more pronounced the smaller the individual values and the more frequent the accesses.

For very large, rare write operations, for example storing a multi-megabyte JSON blob once, the difference narrows somewhat, since raw data volume matters more here than per-call protocol overhead. For the typical use case of small, frequent key-value access, though, MMKV stays clearly ahead in every realistic scenario.

4. API comparison: from AsyncStorage promises to MMKV synchronous calls

The API difference shows up directly in the code: AsyncStorage requires await or a .then() chain for every access, while MMKV provides synchronous methods that return a value immediately, without the calling function itself needing to be asynchronous. This especially simplifies code that wants to read values while rendering, which with a purely asynchronous API is only possible through workarounds like an initial loading state.

The example below compares both APIs directly for the same use case, saving and reading an auth token.


// AsyncStorage: every access is asynchronous
import AsyncStorage from "@react-native-async-storage/async-storage";

async function saveToken(token: string) {
  await AsyncStorage.setItem("auth_token", token);
}

async function loadToken(): Promise<string | null> {
  return AsyncStorage.getItem("auth_token");
}

// MMKV: synchronous access without a promise
import { MMKV } from "react-native-mmkv";

const storage = new MMKV();

function saveTokenSync(token: string) {
  storage.set("auth_token", token);
}

function loadTokenSync(): string | undefined {
  return storage.getString("auth_token");
}

5. Migrating existing AsyncStorage data to MMKV

A migration is usually implemented in practice as a one-time step at app startup: all existing keys are determined via AsyncStorage.getAllKeys(), the corresponding values read through multiGet, and then written synchronously into a new MMKV instance. After a successful migration, a dedicated flag property marks the process as complete so it does not repeat on future app starts.

It matters to make the migration idempotent and to not let error cases like a single failed value abort the entire migration, otherwise users could end up with data partly migrated and partly still sitting in AsyncStorage. A proven pattern is to not delete AsyncStorage immediately after migration, but only after several successful app starts, keeping a way back in case something goes wrong.

6. MMKV's encryption option

MMKV supports built-in encryption, activated when creating an instance through an encryption key, transparently encrypting all data with AES before it is written to the underlying file. For sensitive data like session tokens or personal user information this is a noticeable advantage over AsyncStorage, which ships with no encryption at all by default and relies on additional libraries for that.

The encryption key itself should not sit in plain text in the code, but be managed through a secure secure-storage mechanism like the iOS keychain or the Android keystore, so the encryption is not undermined by an easily readable, hardcoded key. MMKV itself does not manage this key, that remains the app's responsibility.

7. Multi-instance and multi-process support

Unlike a single global AsyncStorage instance, MMKV allows multiple independent, named instances within the same app, which works well for cleanly separating different data categories like user preferences, cache data and auth information, without worrying about key name collisions. Each instance can also get its own encryption configuration.

MMKV also supports multi-process access, which becomes relevant as soon as an app has extensions like an iOS share extension or an Android widget process that need access to the same data as the main process. AsyncStorage offers no built-in mechanism for that and would require its own inter-process communication.

8. Limits of MMKV: large data volumes and complex queries

MMKV is designed as a pure key-value store and offers no way to run structured queries like filtering, sorting or joining multiple records, the way a relational database would. For use cases like a searchable list of thousands of records with complex filter criteria, MMKV is therefore the wrong choice, SQLite or a specialized solution like WatermelonDB fits better here.

For very large individual values too, for example caching entire API responses several megabytes in size, MMKV loses part of its speed advantage, since the mmap-based approach shines mainly with many small, frequent accesses. MMKV remains, at its core, a replacement for AsyncStorage, not a full database for complex, relational requirements.

9. Adding it to a project: installation and New Architecture compatibility

Installing react-native-mmkv happens through the usual package manager, followed by a native build step, since MMKV is built on native C++ code and not shipped as pure JavaScript. On iOS a pod install is required, on Android autolinking picks it up automatically as long as the project configuration is current.

Current versions of react-native-mmkv are explicitly built for the New Architecture with JSI and do not work in pure legacy mode without the New Architecture enabled, since the synchronous API sits directly on top of JSI HostObjects. Projects still running entirely on the old architecture either need to fall back to an older MMKV version or switch to the New Architecture first before adopting MMKV.

Criterion AsyncStorage MMKV Practical meaning
Access type Asynchronous, promise-based Synchronous, direct return value MMKV works for reads during rendering
Speed for small values Comparatively slow Roughly 10 to 30 times faster Clearly noticeable for frequent access
Encryption Not built in, needs an extra library Built-in AES encryption per instance MMKV saves an extra dependency
Multiple instances One global instance Several named, independent instances Clean separation of data categories with MMKV
Fit for large data volumes Limited, meant for small values Also limited, no SQLite replacement Neither fits complex queries well

Mironsoft

React Native app development and Magento integration

A mobile app for the Magento shop that actually runs smoothly?

We build React Native apps cleanly connected to the Magento REST or GraphQL API, from the first line of code to publishing on the App Store and Google Play.

App Concept

Plan the architecture and feature scope of a Magento-connected app together.

Magento API Integration

Cleanly connect product catalog, cart, and checkout to the shop API.

Store Publishing

Guide the App Store and Google Play release process without pitfalls.

10. Summary

MMKV vs. AsyncStorage at a Glance

AsyncStorage

An asynchronous key-value store over a TurboModule, solid for occasional access, but overhead adds up with frequency.

MMKV

A synchronous, C++ and mmap-based store over JSI, noticeably faster for many small accesses.

Migration

AsyncStorage data can be read once at app startup and moved into a new MMKV instance.

Limits

MMKV remains a key-value store without query capabilities, SQLite stays the right choice for complex data models.

11. FAQ: MMKV vs. AsyncStorage at a Glance

1Is MMKV always faster than AsyncStorage?
For small, frequent accesses yes, often by ten to thirty times. For rare, very large values the difference narrows somewhat.
2Can I read MMKV synchronously during render?
Yes, that is one of its main advantages: MMKV methods return values directly, without a promise, which makes them safe to use even outside useEffect.
3Does MMKV work without the New Architecture?
Current versions are explicitly built for JSI and the New Architecture. Without the New Architecture enabled, an older MMKV version must be used instead.
4How do I migrate existing AsyncStorage data to MMKV?
Through a one-time migration step at app startup that reads all keys and values from AsyncStorage and writes them synchronously into a new MMKV instance, guarded by a completion flag.
5Does MMKV offer built-in encryption?
Yes, through an encryption key passed when creating the instance, which transparently encrypts all data with AES before it is stored.
6Where should the MMKV encryption key be stored?
Not hardcoded in the code, but through a secure mechanism like the iOS keychain or the Android keystore, so the key is not easily readable.
7Is MMKV suitable for a large, searchable data list?
No, MMKV is a pure key-value store without query capabilities. For structured, filterable data, SQLite or a specialized solution like WatermelonDB is the better choice.
8Can I use several separate MMKV instances in one app?
Yes, MMKV supports several independent, named instances, which works well for cleanly separating different data categories.
9Does MMKV support access from app extensions like widgets?
Yes, through multi-process support, which AsyncStorage does not offer without its own inter-process communication.
10Should I replace AsyncStorage entirely with MMKV?
For most key-value use cases the switch is worth it, especially with frequent access. For rare, non-critical single accesses the difference is often negligible in practice.