React Native MMKV vs AsyncStorage i 2026: Hurtig key-value storage guide

react-native-mmkv er 20-30x hurtigere end AsyncStorage takket være JSI. Guiden dækker installation, typede hooks, AES-256-kryptering og en sikker migreringssti med kodeeksempler fra produktion.

MMKV vs AsyncStorage Guide (2026)

Opdateret: 13. september 2026

Kort svar: react-native-mmkv er 20–30x hurtigere end AsyncStorage til synkron key-value-lagring, fordi biblioteket bygger på Tencents C++ MMKV og bruger JSI direkte i stedet for at gå gennem den asynkrone bridge. I 2026, hvor den nye arkitektur (Fabric + TurboModules) er standard i React Native 0.79+, er MMKV det pragmatiske valg til alt, der ikke er en relationel database eller en secret. Denne guide viser installation, typede hooks, kryptering, migreringssti fra AsyncStorage og de faldgruber, jeg konsekvent ser i produktion.

  • MMKV v3 er synkron og bygger på JSI (ingen Promise-wrapping, ingen bridge-overhead), målt til ~0,0006 ms per læsning på iOS.
  • AsyncStorage er asynkront og gemmer JSON-strenge på disk (SQLite på Android, dictionary på iOS). Solidt til små, ikke-hyppige skrivninger, men langsomt til alt andet.
  • MMKV understøtter AES-256-kryptering indbygget og har typede React-hooks (useMMKVString, useMMKVObject) med automatisk re-render.
  • Migrering kræver en engangs-læsning af AsyncStorage-nøgler ved app-start. Sæt et hasMigrated-flag i MMKV, så du undgår at gøre det to gange.
  • Brug SecureStore til tokens og passwords, MMKV til alt andet lokalt state, og SQLite/WatermelonDB når du har relationelle data eller mere end ~10 MB.

Hvad er MMKV, og hvorfor bruger React Native-teams det?

MMKV står for Memory-Mapped Key-Value og er et open source key-value-bibliotek, som Tencent open-sourcede i 2018. Det driver WeChat på over en milliard enheder og bruger mmap() til at mappe en fil direkte ind i processens virtuelle hukommelse. Det betyder, at læsninger og skrivninger går gennem OS'ets page cache uden et eksplicit disk-I/O-hop per operation, og at kernel selv står for at synkronisere ændringerne til disk.

react-native-mmkv, vedligeholdt af Marc Rousavy, wrapper dette bibliotek som et JSI-modul. Fordi JSI (JavaScript Interface) lader JavaScript kalde C++ synkront uden at serialisere til den gamle bridge, ser din JavaScript-kode MMKV som en almindelig synkron funktion. Det ligner mere localStorage i browseren end AsyncStorage. På et Pixel 6-benchmark læser MMKV en nøgle på ca. 0,0007 ms, mens AsyncStorage bruger 4–8 ms på samme operation. Forskellen er ikke akademisk. Læser du 20 preferences ved cold start, sparer du potentielt 100+ ms før første render.

Ærligt talt: i min egen fintech-app flyttede vi 43 feature flags og bruger-preferences fra AsyncStorage til MMKV som led i migreringen til den nye arkitektur. Time-to-interactive faldt målbart, og vi fjernede alle de useEffect(() => { AsyncStorage.getItem(...).then(setState) }, [])-mønstre, fordi MMKV kan læses synkront i selve komponent-body'en. Det ryddede omkring 15 filer for boilerplate på én eftermiddag.

MMKV vs AsyncStorage: Sammenligning og benchmarks

De to biblioteker løser samme problem, nemlig persistent key-value-lagring, men arkitektonisk er de ikke i samme liga. Sådan står de side om side i 2026:

Egenskabreact-native-mmkv v3@react-native-async-storage/async-storage v2
API-stilSynkron (JSI)Asynkron (Promise)
Backing storemmap-fil (C++/native)SQLite (Android), dictionary-fil (iOS)
Læsning per nøgle~0,0007 ms~4–8 ms
Skrivning per nøgle~0,002 ms~10–20 ms
KrypteringAES-256 indbyggetKun via ekstern lib
Typede React-hooksJa (useMMKVString, useMMKVObject)Nej (byg selv)
Understøtter Expo GoNej (kræver dev-client eller EAS Build)Ja
Ny arkitektur (Fabric/TurboModules)Ja (JSI-native)Ja (siden v2)
Multi-instance / namespacesJaNej
Bundle size (Android)~50 KB~20 KB

Bemærk, at AsyncStorage stadig er den rette default for Expo Go-projekter og for hobby-apps, hvor du ikke vil røre native builds. Men så snart du kører dev-client eller EAS Build alligevel (og det gør enhver produktions-app), er MMKV nærmest en gratis frokost. Hvis du vil grave dybere i, hvorfor JSI er så meget hurtigere end den gamle bridge, kan du læse min gennemgang af React Natives nye arkitektur og JSI.

Installation af react-native-mmkv v3 (Expo og bare)

I 2026 er MMKV oppe på v3.x, som kræver den nye arkitektur og React Native 0.74+. Hvis du stadig kører den gamle arkitektur, skal du bruge v2.x, men vær opmærksom på, at v2 er i vedligeholdelsestilstand og ikke får nye features.

Expo (managed workflow med dev-client)

npx expo install react-native-mmkv
npx expo prebuild --clean
npx expo run:ios   # eller run:android

MMKV virker ikke i Expo Go, fordi det er et native module. Du skal enten køre gennem expo run eller bygge en dev-client via EAS. Hvis dit team stadig er på Expo Go, er det her et fint tidspunkt at flytte til dev-client. Det låser resten af native-økosystemet op også.

Bare React Native (0.74+)

yarn add react-native-mmkv
cd ios && pod install && cd ..
yarn ios

Ingen manuel linking, ingen native-side ændringer. Codegen samler bindings under en yarn ios-build, og JSI-runtime'en registrerer modulet ved app-start.

Grundlæggende API og typede hooks

MMKV eksponerer to måder at bruge biblioteket på: en imperativ storage-instans og et sæt React-hooks, der giver dig reaktive værdier ud af boksen.

Imperativ API

import { MMKV } from 'react-native-mmkv'

export const storage = new MMKV({
  id: 'user-preferences',
  encryptionKey: 'ikke-hardcod-mig-i-produktion',
})

storage.set('theme', 'dark')
storage.set('userId', 42)
storage.set('onboarded', true)

const theme = storage.getString('theme')          // 'dark'
const userId = storage.getNumber('userId')        // 42
const onboarded = storage.getBoolean('onboarded') // true

storage.delete('theme')
storage.clearAll()

Bemærk, at læsninger returnerer værdien direkte. Der er ingen await. Det betyder også, at du kan læse fra MMKV i selve komponentens render-funktion uden at pakke det ind i useEffect eller Suspense.

React-hooks med typet auto-update

import { useMMKVString, useMMKVBoolean, useMMKVObject } from 'react-native-mmkv'

type UserPrefs = { theme: 'light' | 'dark'; fontSize: number }

function SettingsScreen() {
  const [theme, setTheme] = useMMKVString('theme')
  const [notifications, setNotifications] = useMMKVBoolean('notifications')
  const [prefs, setPrefs] = useMMKVObject<UserPrefs>('prefs')

  return (
    <Switch value={notifications ?? false}
            onValueChange={setNotifications} />
  )
}

Når en anden komponent kalder setTheme('light'), re-renderer alle hooks abonneret på nøglen 'theme' automatisk. Det er en billig erstatning for en fuld global state manager, hvis du bare skal dele et par preferences på tværs af skærme. Til større state anbefaler jeg stadig Zustand eller Redux Toolkit, men MMKV-hooks alene dækker overraskende mange use cases.

Kryptering med MMKV: AES-256 uden Keychain-boilerplate

En af de mest undervurderede MMKV-features er indbygget AES-256-CFB-kryptering. Du passerer bare en encryptionKey til constructor, og alle nøgler og værdier krypteres transparent, før de rører disken.

import { MMKV } from 'react-native-mmkv'
import * as Keychain from 'react-native-keychain'

async function createEncryptedStorage() {
  let creds = await Keychain.getGenericPassword({ service: 'mmkv-key' })
  if (!creds) {
    const key = generateSecureRandomKey(32) // fx via expo-crypto
    await Keychain.setGenericPassword('mmkv', key, { service: 'mmkv-key' })
    creds = { username: 'mmkv', password: key, service: 'mmkv-key', storage: 'kc' }
  }
  return new MMKV({ id: 'secure-store', encryptionKey: creds.password })
}

Bemærk mønsteret. Selve krypteringsnøglen gemmes i iOS Keychain eller Android Keystore (via react-native-keychain eller expo-secure-store), og først derefter bruges den til at åbne MMKV. Hardkod aldrig nøglen i din bundle. Den ville trivielt kunne udpakkes fra en dekompileret APK.

Migrering fra AsyncStorage til MMKV uden datatab

Den mest almindelige situation, jeg møder, er en eksisterende app med 50–200 AsyncStorage-nøgler, som teamet vil flytte til MMKV. Fremgangsmåden er en one-shot migration ved første app-start efter opdateringen.

import AsyncStorage from '@react-native-async-storage/async-storage'
import { MMKV } from 'react-native-mmkv'

export const storage = new MMKV()

export async function migrateAsyncStorage() {
  if (storage.getBoolean('__migrated_from_async_storage__')) return

  const keys = await AsyncStorage.getAllKeys()
  const pairs = await AsyncStorage.multiGet(keys)

  for (const [key, value] of pairs) {
    if (value === null) continue
    // Alt fra AsyncStorage er JSON-strenge, så læs som string først
    storage.set(key, value)
  }

  storage.set('__migrated_from_async_storage__', true)
  // Behold AsyncStorage i én release som failsafe, ryd op i næste
}

Kør denne funktion fra din root-komponent, før første skærm mountes. Jeg foretrækker at kalde den fra en useEffect med et splash-screen på, indtil den er færdig. For 200 nøgler tager det under 20 ms, men splash-screenet undgår en race condition, hvor UI læser fra en tom MMKV. Jeg ramte præcis den bug første gang, jeg sendte migreringen i produktion uden splash, så tag den advarsel alvorligt.

Vent én release med at slette AsyncStorage-koden. Hvis migreringen fejler for én enkelt bruger, kan du rulle tilbage til AsyncStorage-læsning uden datatab. Fra release to og fremad kan du fjerne dependency helt.

Hvornår skal du vælge MMKV, SecureStore eller SQLite?

MMKV er ikke svaret på alt. Her er den beslutningsmatrix, jeg giver mine team leads:

  • MMKV: User preferences, feature flags, cached UI state, små blobs (<1 MB), navigation persistence, onboarding-flags, sprogvalg. Alt hvor du vil læse synkront ved cold start.
  • SecureStore / Keychain: Auth tokens, refresh tokens, API-keys, bruger-passwords, betalingsdata. Ting hvor OS-niveau kryptering med biometrisk gating er værd at have.
  • SQLite (via react-native-quick-sqlite eller op-sqlite): Relationelle data, chat-historik, offline-queues med tusindvis af rows, komplekse queries.
  • WatermelonDB: Reactive ORM oven på SQLite. God når du har både relationelle data og skal binde dem til React-komponenter.
  • Filsystem (via expo-file-system): Store binære assets, video, downloaded PDF'er, altså alt over ~1 MB.

Er din datastruktur en flad key-value-map, og har du brug for både persistens og reaktivitet, så er MMKV næsten altid det rigtige valg. Hvis du allerede bruger TanStack Query til data-fetching og caching, kan du kombinere: TanStack Query's persister kan pege på MMKV som backing store, så din query-cache overlever cold start.

Almindelige faldgruber i produktion

Efter to års erfaring med MMKV i en app på 400.000 månedlige aktive brugere er her de fem problemer, jeg har set mest:

1. At bruge MMKV til store objekter

MMKV er optimeret til mange små nøgler, ikke få store. Hvis du gemmer et 500 KB JSON-blob, betaler du en serialiserings-cost hver gang det opdateres, og hele filen re-writes. Split det op i mindre nøgler eller flyt til SQLite.

2. At glemme, at MMKV er synkron

Det er en feature, indtil du kalder storage.getAllKeys() på et objekt med 10.000 nøgler under render. Så blokerer du main thread. Batch store operationer i en InteractionManager.runAfterInteractions-blok, eller flyt dem til en worklet.

3. Multiple instanser med samme id

Hvis du opretter new MMKV({ id: 'foo' }) flere steder, får du forskellige JavaScript-wrapper-objekter, men samme underliggende fil. Det er OK i sig selv, men jeg foretrækker at eksportere én single instance fra en storage.ts-fil for at undgå, at flere komponenter bruger forskellige encryption keys ved et uheld.

4. Ikke at kryptere selve encryption keyen

At gemme AES-nøglen som en literal streng i din kildekode gør krypteringen værdiløs. Nøglen skal komme fra Keychain eller Keystore, og den skal genereres ved første app-start med en kryptografisk sikker RNG (expo-crypto's getRandomBytesAsync).

5. At teste med Jest uden mock

Jest kører i Node uden JSI, så MMKV-kald crasher. Løsningen er en mock i jest.setup.js:

jest.mock('react-native-mmkv', () => ({
  MMKV: jest.fn().mockImplementation(() => {
    const store = new Map()
    return {
      set: (k, v) => store.set(k, v),
      getString: (k) => store.get(k),
      getNumber: (k) => store.get(k),
      getBoolean: (k) => store.get(k),
      delete: (k) => store.delete(k),
      clearAll: () => store.clear(),
    }
  }),
}))

Se min komplette debugging- og test-guide for flere Jest-mønstre til native modules.

Ofte stillede spørgsmål

Er MMKV virkelig hurtigere end AsyncStorage?

Ja, målt til 20–30x hurtigere for både læsning og skrivning i tredjeparts-benchmarks. Forskellen kommer fra JSI (synkron C++-kald uden Promise-serialisering) og fra memory-mapped I/O i stedet for SQLite. På store nøglemængder er forskellen mindre dramatisk, men for typiske key-value-brug er MMKV altid hurtigere.

Virker MMKV med Expo?

Ja, men ikke i Expo Go. Du skal bruge en dev-client (via EAS Build eller expo run) eller den bare workflow. For projekter, der allerede kører EAS Build til produktion, er der ingen ekstra opsætning. Kør bare npx expo install react-native-mmkv og en prebuild.

Kan MMKV krypteres?

Ja, MMKV understøtter AES-256-CFB-kryptering indbygget. Pass en encryptionKey-streng til constructor, og alle værdier krypteres transparent på disken. Krypteringsnøglen bør selv gemmes i iOS Keychain eller Android Keystore, aldrig hardkodet i din bundle.

Understøtter MMKV den nye arkitektur (Fabric og TurboModules)?

Ja. react-native-mmkv v3 kræver faktisk den nye arkitektur og React Native 0.74+. Modulet er skrevet som et JSI-native modul og drager fuld fordel af direkte C++-til-JavaScript-kald uden bridge-overhead.

Hvordan migrerer jeg fra AsyncStorage til MMKV uden at miste brugerdata?

Kør en engangs-migration ved app-start: læs alle AsyncStorage-nøgler med getAllKeys() og multiGet(), skriv dem til MMKV, og sæt et hasMigrated-flag. Behold AsyncStorage som dependency i én release som failsafe, og fjern den derefter helt.

Yelena Petrov
Om Forfatteren Yelena Petrov

React Native architect at a fintech. Builds platform teams, type-safe bridges, and runs the upgrade playbook so others don't have to.