Stan.js provides first-class support for react-native-mmkv , a fast, secure, and efficient storage solution for React Native applications. MMKV is significantly faster than AsyncStorage and supports encryption out of the box.
Installation
First, install the required dependencies:
npm install react-native-mmkv
For iOS, install pods:
Stan.js automatically detects and supports both MMKV v2 and v3, so you don’t need to change your code when upgrading.
Basic Usage
Import storage from the native path:
import { createStore } from 'stan-js'
import { storage } from 'stan-js/storage/native'
export const { useStore } = createStore ({
theme: storage ( 'light' ),
user: storage ({ id: '' , name: '' }),
token: storage ( '' )
})
Custom MMKV Instance
Create a custom MMKV instance for advanced configuration:
import { createStore } from 'stan-js'
import { createStorage } from 'stan-js/storage/native'
import { MMKV } from 'react-native-mmkv'
// Create MMKV instance with custom configuration
const mmkvInstance = new MMKV ({
id: 'user-storage' ,
encryptionKey: 'your-encryption-key'
})
// Create storage with custom MMKV instance
const storage = createStorage ({
mmkvInstance
})
export const { useStore } = createStore ({
authToken: storage ( '' ),
sensitiveData: storage ({ apiKey: '' , secret: '' })
})
Configuration Options
MMKV supports various configuration options:
Unique identifier for the MMKV instance. Allows you to create multiple isolated storage instances. const userMMKV = new MMKV ({ id: 'user-data' })
const cacheMMKV = new MMKV ({ id: 'cache-data' })
Encryption key for securing stored data. When provided, all data is encrypted using AES. const secureMMKV = new MMKV ({
id: 'secure-storage' ,
encryptionKey: 'my-secret-key-from-keychain'
})
Custom directory path for storing MMKV files. Defaults to app’s document directory. const customPathMMKV = new MMKV ({
id: 'custom-storage' ,
path: '/custom/path/to/storage'
})
Examples
Encrypted Authentication Storage
import { createStore } from 'stan-js'
import { createStorage } from 'stan-js/storage/native'
import { MMKV } from 'react-native-mmkv'
import * as Keychain from 'react-native-keychain'
// Get encryption key from secure keychain
const getEncryptionKey = async () => {
const credentials = await Keychain . getGenericPassword ()
return credentials ? credentials . password : 'default-key'
}
// Create encrypted MMKV instance
const encryptionKey = await getEncryptionKey ()
const secureMMKV = new MMKV ({
id: 'auth-storage' ,
encryptionKey
})
const secureStorage = createStorage ({
mmkvInstance: secureMMKV
})
export const { useStore } = createStore ({
accessToken: secureStorage ( '' ),
refreshToken: secureStorage ( '' ),
userCredentials: secureStorage ({ username: '' , encryptedPassword: '' })
})
Multiple Storage Instances
import { createStore } from 'stan-js'
import { createStorage } from 'stan-js/storage/native'
import { MMKV } from 'react-native-mmkv'
// User data storage
const userMMKV = new MMKV ({ id: 'user-data' })
const userStorage = createStorage ({ mmkvInstance: userMMKV })
// Cache storage (can be cleared separately)
const cacheMMKV = new MMKV ({ id: 'cache-data' })
const cacheStorage = createStorage ({ mmkvInstance: cacheMMKV })
// App settings storage
const settingsMMKV = new MMKV ({ id: 'app-settings' })
const settingsStorage = createStorage ({ mmkvInstance: settingsMMKV })
export const { useStore } = createStore ({
// User data
user: userStorage ({ id: '' , name: '' , email: '' }),
profile: userStorage ({ avatar: '' , bio: '' }),
// Cache
apiCache: cacheStorage ({}),
imageUrls: cacheStorage ([]),
// Settings
theme: settingsStorage ( 'light' ),
language: settingsStorage ( 'en' ),
notifications: settingsStorage ( true )
})
// Clear cache without affecting user data
export const clearCache = () => {
cacheMMKV . clearAll ()
}
Global Serialization with MMKV
import { createStore } from 'stan-js'
import { createStorage } from 'stan-js/storage/native'
import { MMKV } from 'react-native-mmkv'
import superjson from 'superjson'
const mmkvInstance = new MMKV ({ id: 'app-storage' })
const storage = createStorage ({
mmkvInstance ,
serialize: superjson . stringify ,
deserialize: superjson . parse
})
export const { useStore } = createStore ({
// Can now store Date, Map, Set, etc.
lastSync: storage ( new Date ()),
userMap: storage ( new Map ()),
tags: storage ( new Set ())
})
Hybrid Web/Native Support
import { createStore } from 'stan-js'
import { Platform } from 'react-native'
// Import the correct storage based on platform
const storage = Platform . select ({
native : () => require ( 'stan-js/storage/native' ). storage ,
default : () => require ( 'stan-js/storage' ). storage
})()
export const { useStore } = createStore ({
theme: storage ( 'light' ),
settings: storage ({ notifications: true })
})
MMKV Version Compatibility
Stan.js automatically handles differences between MMKV v2 and v3:
MMKV v2
import { MMKV } from 'react-native-mmkv'
// v2 uses createMMKV()
const storage = MMKV . createMMKV ()
MMKV v3
import { MMKV } from 'react-native-mmkv'
// v3 uses new MMKV()
const storage = new MMKV ()
Stan.js detects the version automatically and uses the appropriate API. No code changes needed when upgrading.
Implementation Details
The MMKV adapter is implemented in src/storage/mmkvFactory.ts:
import mmkv from 'react-native-mmkv'
import { CreateStorageOptions , StorageOptions , Synchronizer } from '../types'
type MMKV_V3 = {
MMKV : new () => mmkv . MMKV
}
// Auto-detect and create appropriate MMKV instance
const DefaultMMKV : mmkv . MMKV = 'createMMKV' in mmkv
? mmkv . createMMKV () // v2
: Object . assign ( new ( mmkv as MMKV_V3 ). MMKV (), { // v3
remove ( this : mmkv . MMKV , key : string ) {
this . delete ( key ) // v3 renamed remove to delete
},
})
export const createStorage = ( storageOptions ?: CreateStorageOptions ) =>
< T >(
initialValue : T ,
{
deserialize = storageOptions ?. deserialize ?? JSON . parse ,
serialize = storageOptions ?. serialize ?? JSON . stringify ,
storageKey ,
}: StorageOptions < T > = {},
) => {
const mmkv = storageOptions ?. mmkvInstance ?? DefaultMMKV
return {
value: initialValue ,
update : ( value , key ) => {
const storageKeyToUse = storageKey ?? key
if ( value === undefined ) {
mmkv . remove ( storageKeyToUse )
return
}
mmkv . set ( storageKeyToUse , serialize ( value ))
},
getSnapshot : key => {
const value = mmkv . getString ( storageKey ?? key )
if ( value === undefined ) {
throw new Error () // Value not in storage
}
return deserialize ( value )
},
} as Synchronizer < T >
}
MMKV offers significant performance improvements over AsyncStorage:
Synchronous operations : No async/await overhead
Memory mapping : Direct file access without serialization overhead
Lazy loading : Only loads values when accessed
Efficient updates : Only writes changed data
import { createStore } from 'stan-js'
import { storage } from 'stan-js/storage/native'
// All operations are synchronous and fast
export const { useStore , actions } = createStore ({
counter: storage ( 0 )
})
// Fast synchronous updates
actions . setCounter ( prev => prev + 1 )
actions . setCounter ( prev => prev + 1 )
actions . setCounter ( prev => prev + 1 )
// All changes are immediately persisted
Migration from AsyncStorage
If you’re migrating from AsyncStorage:
// Before (with AsyncStorage)
import AsyncStorage from '@react-native-async-storage/async-storage'
const loadData = async () => {
const value = await AsyncStorage . getItem ( 'key' )
return JSON . parse ( value || 'null' )
}
const saveData = async ( data ) => {
await AsyncStorage . setItem ( 'key' , JSON . stringify ( data ))
}
// After (with Stan.js + MMKV)
import { createStore } from 'stan-js'
import { storage } from 'stan-js/storage/native'
export const { useStore } = createStore ({
data: storage ( null )
})
// Everything is automatic and synchronous!
function MyComponent () {
const { data , setData } = useStore ()
return < Text >{JSON.stringify(data)} </ Text >
}
storage Pre-configured storage wrapper
createStorage Factory function for custom storage instances
React Native Example Complete React Native example with MMKV
Persistence Guide Complete guide to data persistence