react-native-nitro-storage
The fastest, most complete storage solution for React Native.
Synchronous Memory, Disk, and Secure storage in one unified API — powered by Nitro Modules and JSI.
Highlights
- Three storage scopes — in-memory, persistent disk, and hardware-encrypted secure storage
- Synchronous reads & writes — no
async/await, no bridge, zero serialization overhead for primitives
- React hooks —
useStorage, useStorageSelector, useSetStorage with automatic re-renders
- Type-safe — full TypeScript generics, custom serializers, schema validation with fallback
- Namespaces — isolate keys by feature, user, or tenant with automatic prefixing
- TTL expiration — time-based auto-expiry with optional
onExpired callback
- Biometric storage — hardware-backed biometric protection on iOS & Android
- Auth storage factory —
createSecureAuthStorage for multi-token auth flows
- Batch operations — atomic multi-key get/set/remove via native batch APIs
- Prefix queries — fast key/value scans with
storage.getKeysByPrefix and storage.getByPrefix
- Versioned writes — optimistic concurrency with
item.getWithVersion() and item.setIfVersion(...)
- Performance metrics — observe operation timings and aggregate snapshots
- Web secure backend override — plug custom secure storage backend on web
- IndexedDB backend — drop-in
createIndexedDBBackend factory for persistent web Secure storage with large payloads
- Bulk import — load a raw
Record<string, string> into any scope atomically with storage.import
- Transactions — grouped writes with automatic rollback on error
- Migrations — versioned data migrations with
registerMigration / migrateToLatest
- MMKV migration — drop-in
migrateFromMMKV for painless migration from MMKV
- Cross-platform — iOS, Android, and web (
localStorage fallback)
Feature Coverage
Every feature in this package is documented with at least one runnable example in this README:
- Core item API (
createStorageItem, get/set/delete/has/subscribe) — see Quick Start and Low-level subscription use case
- Hooks (
useStorage, useStorageSelector, useSetStorage) — see Quick Start and Persisted User Preferences
- Scopes (
Memory, Disk, Secure) — see Storage Scopes and multiple use cases
- Namespaces — see Multi-Tenant / Namespaced Storage
- TTL expiration + callbacks — see OTP / Temporary Codes
- Validation + recovery — see Feature Flags with Validation
- Biometric + access control — see Biometric-protected Secrets
- Global storage utilities (
clear*, has, getAll*, size, secure write settings) — see Global utility examples and Storage Snapshots and Cleanup
- Prefix utilities (
getKeysByPrefix, getByPrefix) — see Prefix Queries and Namespace Inspection
- Versioned item API (
getWithVersion, setIfVersion) — see Optimistic Versioned Writes
- Metrics API (
setMetricsObserver, getMetricsSnapshot, resetMetrics) — see Storage Metrics Instrumentation
- Web secure backend override (
setWebSecureStorageBackend, getWebSecureStorageBackend) — see Custom Web Secure Backend
- IndexedDB backend factory (
createIndexedDBBackend) — see IndexedDB Backend for Web
- Bulk import (
storage.import) — see Bulk Data Import
- Batch APIs (
getBatch, setBatch, removeBatch) — see Batch Operations and Bulk Bootstrap with Batch APIs
- Transactions — see Transactions and Atomic Balance Transfer
- Migrations (
registerMigration, migrateToLatest) — see Migrations
- MMKV migration (
migrateFromMMKV) — see MMKV Migration and Migrating From MMKV
- Raw string API (
getString, setString, deleteString) — see Raw String API
- Keychain locked detection (
isKeychainLockedError) — see isKeychainLockedError(err)
- Auth storage factory (
createSecureAuthStorage) — see Auth Token Management
Requirements
react-native | >= 0.75.0 |
react-native-nitro-modules | >= 0.35.4 |
react | >= 18.2.0 |
Installation
bun add react-native-nitro-storage react-native-nitro-modules
or:
npm install react-native-nitro-storage react-native-nitro-modules
Expo
bunx expo install react-native-nitro-storage react-native-nitro-modules
Add the config plugin to app.json:
{
"expo": {
"plugins": [
[
"react-native-nitro-storage",
{
"faceIDPermission": "Allow $(PRODUCT_NAME) to use Face ID for secure authentication",
"addBiometricPermissions": false
}
]
]
}
}
faceIDPermission sets NSFaceIDUsageDescription only when missing. Android biometric permissions are opt-in via addBiometricPermissions: true.
Then run:
bunx expo prebuild
Bare React Native
iOS:
cd ios && pod install
Android — initialize the native adapter in MainApplication.kt:
import com.nitrostorage.AndroidStorageAdapter
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
AndroidStorageAdapter.init(this)
}
}
Quick Start
import { createStorageItem, StorageScope, useStorage } from "react-native-nitro-storage";
const counterItem = createStorageItem({
key: "counter",
scope: StorageScope.Memory,
defaultValue: 0,
});
export function Counter() {
const [count, setCount] = useStorage(counterItem);
return (
<Button
title={`Count: ${count}`}
onPress={() => setCount((prev) => prev + 1)}
/>
);
}
Storage Scopes
Memory | In-process JS Map | In-process JS Map | In-process JS Map | No |
Disk | UserDefaults (app suite) | SharedPreferences | localStorage | Yes |
Secure | Keychain (AES-256 GCM) | EncryptedSharedPreferences | localStorage (__secure_ + __bio_ prefixes) | Yes |
import { StorageScope } from "react-native-nitro-storage";
StorageScope.Memory;
StorageScope.Disk;
StorageScope.Secure;
API Reference
createStorageItem<T>(config)
The core factory. Creates a reactive storage item that can be used standalone or with hooks.
function createStorageItem<T = undefined>(
config: StorageItemConfig<T>,
): StorageItem<T>;
Config options:
key | string | required | Storage key identifier |
scope | StorageScope | required | Where to store the data |
defaultValue | T | undefined | Value returned when no data exists |
serialize | (value: T) => string | JSON fast path | Custom serialization |
deserialize | (value: string) => T | JSON fast path | Custom deserialization |
validate | (value: unknown) => value is T | — | Type guard run on every read |
onValidationError | (invalidValue: unknown) => T | — | Recovery function when validation fails |
expiration | { ttlMs: number } | — | Time-to-live in milliseconds |
onExpired | (key: string) => void | — | Callback fired when a TTL value expires on read |
readCache | boolean | false | Cache deserialized values in JS (avoids repeated native reads) |
coalesceSecureWrites | boolean | false | Batch same-tick Secure writes per key |
namespace | string | — | Prefix key as namespace:key for isolation |
biometric | boolean | false | Require biometric auth (Secure scope only) |
biometricLevel | BiometricLevel | None | Biometric policy (BiometryOrPasscode / BiometryOnly) |
accessControl | AccessControl | — | Keychain access control level (native only) |
Returned StorageItem<T>:
get() | () => T | Read current value (synchronous) |
getWithVersion() | () => { value: T; version: StorageVersion } | Read value plus current storage version token |
set(value) | (value: T | ((prev: T) => T)) => void | Write a value or updater function |
setIfVersion(...) | (version: StorageVersion, value: T | ((prev: T) => T)) => boolean | Write only if version matches (optimistic concurrency) |
delete() | () => void | Remove the stored value (resets to defaultValue) |
has() | () => boolean | Check if a value exists in storage |
subscribe(cb) | (cb: () => void) => () => void | Listen for changes, returns unsubscribe |
serialize | (v: T) => string | The item's serializer |
deserialize | (v: string) => T | The item's deserializer |
scope | StorageScope | The item's scope |
key | string | The resolved key (includes namespace prefix) |
Non-React subscription example:
const unsubscribe = sessionItem.subscribe(() => {
console.log("session changed:", sessionItem.get());
});
sessionItem.set("next-session");
unsubscribe();
React Hooks
useStorage(item)
Full reactive binding. Re-renders when the value changes.
const [value, setValue] = useStorage(item);
useStorageSelector(item, selector, isEqual?)
Subscribe to a derived slice. Only re-renders when the selected value changes.
const [theme, setSettings] = useStorageSelector(settingsItem, (s) => s.theme);
useSetStorage(item)
Write-only hook. Useful when a component needs to update a value but doesn't depend on it.
const setToken = useSetStorage(tokenItem);
setToken("new-token");
storage — Global Utilities
import { storage, StorageScope } from "react-native-nitro-storage";
storage.clear(scope) | Clear all keys in a scope (Secure also clears biometric entries) |
storage.clearAll() | Clear Memory + Disk + Secure |
storage.clearNamespace(ns, scope) | Remove only keys matching a namespace |
storage.clearBiometric() | Remove all biometric-prefixed keys |
storage.has(key, scope) | Check if a key exists |
storage.getAllKeys(scope) | Get all key names |
storage.getKeysByPrefix(prefix, scope) | Get keys that start with a prefix |
storage.getByPrefix(prefix, scope) | Get raw key-value pairs for keys matching a prefix |
storage.getAll(scope) | Get all key-value pairs as Record<string, string> |
storage.size(scope) | Number of stored keys |
storage.setAccessControl(level) | Set default secure access control for subsequent secure writes (native only) |
storage.setSecureWritesAsync(enabled) | Toggle async secure writes on Android (false by default) |
storage.flushSecureWrites() | Force flush of queued secure writes when coalescing is enabled |
storage.setKeychainAccessGroup(group) | Set keychain access group for app sharing (native only) |
storage.getString(key, scope) | Read a raw string value directly (bypasses serialization) |
storage.setString(key, value, scope) | Write a raw string value directly (bypasses serialization) |
storage.deleteString(key, scope) | Delete a raw string value by key |
storage.import(data, scope) | Bulk-load a Record<string, string> of raw key/value pairs into a scope |
storage.setMetricsObserver(observer?) | Subscribe to per-operation timing events |
storage.getMetricsSnapshot() | Get aggregate counters/latency stats keyed by operation |
storage.resetMetrics() | Reset in-memory metrics counters |
storage.getAll(StorageScope.Secure) returns regular secure entries. Biometric-protected values are not included in this snapshot API.
Global utility examples
import {
AccessControl,
storage,
StorageScope,
} from "react-native-nitro-storage";
storage.has("session", StorageScope.Disk);
storage.getAllKeys(StorageScope.Disk);
storage.getKeysByPrefix("user-42:", StorageScope.Disk);
storage.getByPrefix("user-42:", StorageScope.Disk);
storage.getAll(StorageScope.Disk);
storage.size(StorageScope.Disk);
storage.clearNamespace("user-42", StorageScope.Disk);
storage.clearBiometric();
storage.setAccessControl(AccessControl.WhenUnlockedThisDeviceOnly);
storage.setKeychainAccessGroup("group.com.example.shared");
storage.clear(StorageScope.Memory);
storage.clearAll();
Android secure write mode
storage.setSecureWritesAsync(true) switches secure writes from synchronous commit() to asynchronous apply() on Android.
Use this for non-critical secure writes when lower latency matters more than immediate durability.
Call storage.flushSecureWrites() when you need deterministic persistence boundaries (for example before namespace clears, process handoff, or strict test assertions).
import { storage } from "react-native-nitro-storage";
storage.setSecureWritesAsync(true);
storage.flushSecureWrites();
Custom web secure backend
By default, web Secure scope uses localStorage with __secure_ key prefixing. You can replace it with a custom backend (for example encrypted IndexedDB adapter).
import {
getWebSecureStorageBackend,
setWebSecureStorageBackend,
} from "react-native-nitro-storage";
setWebSecureStorageBackend({
getItem: (key) => encryptedStore.get(key) ?? null,
setItem: (key, value) => encryptedStore.set(key, value),
removeItem: (key) => encryptedStore.delete(key),
clear: () => encryptedStore.clear(),
getAllKeys: () => encryptedStore.keys(),
});
const backend = getWebSecureStorageBackend();
console.log("custom backend active:", backend !== undefined);
IndexedDB Backend for Web
The default web Secure backend uses localStorage, which is synchronous and size-limited. For large payloads or when you need true persistence across tab reloads, use the built-in IndexedDB-backed factory.
import { setWebSecureStorageBackend } from "react-native-nitro-storage";
import { createIndexedDBBackend } from "react-native-nitro-storage/indexeddb-backend";
const backend = await createIndexedDBBackend();
setWebSecureStorageBackend(backend);
How it works:
- Async init:
createIndexedDBBackend() opens (or creates) the IndexedDB database and hydrates an in-memory cache from all stored entries before resolving.
- Synchronous reads: all
getItem calls are served from the in-memory cache — no async overhead after init.
- Fire-and-forget writes:
setItem, removeItem, and clear update the cache synchronously, then persist to IndexedDB in the background. The cache is always the authoritative source.
- Custom database/store: optionally pass
dbName and storeName to isolate databases per environment or tenant.
const backend = await createIndexedDBBackend("my-app-db", "secure-kv");
setWebSecureStorageBackend(backend);
createSecureAuthStorage<K>(config, options?)
One-liner factory for authentication flows. Creates multiple StorageItem<string> entries in Secure scope.
function createSecureAuthStorage<K extends string>(
config: SecureAuthStorageConfig<K>,
options?: { namespace?: string },
): Record<K, StorageItem<string>>;
- Default namespace:
"auth"
- Each key is a separate
StorageItem<string> with StorageScope.Secure
- Supports per-key TTL, biometric level policy, and access control
Batch Operations
Atomic multi-key operations. Uses native batch APIs for best performance.
import { getBatch, setBatch, removeBatch } from "react-native-nitro-storage";
const [a, b, c] = getBatch([itemA, itemB, itemC], StorageScope.Disk);
setBatch(
[
{ item: itemA, value: "hello" },
{ item: itemB, value: "world" },
],
StorageScope.Disk,
);
removeBatch([itemA, itemB], StorageScope.Disk);
All items in a batch must share the same scope. Items with validate or expiration automatically use per-item paths to preserve semantics.
Transactions
Grouped writes with automatic rollback on error.
import { runTransaction, StorageScope } from "react-native-nitro-storage";
runTransaction(StorageScope.Disk, (tx) => {
const balance = tx.getItem(balanceItem);
tx.setItem(balanceItem, balance - 50);
tx.setItem(logItem, `Deducted 50 at ${new Date().toISOString()}`);
if (balance - 50 < 0) throw new Error("Insufficient funds");
});
TransactionContext methods:
getItem(item) | Read a StorageItem's value |
setItem(item, value) | Write a StorageItem's value |
removeItem(item) | Delete a StorageItem |
getRaw(key) | Read raw string by key |
setRaw(key, value) | Write raw string by key |
removeRaw(key) | Delete raw key |
Migrations
Versioned, sequential data migrations.
import {
registerMigration,
migrateToLatest,
StorageScope,
} from "react-native-nitro-storage";
registerMigration(1, ({ setRaw }) => {
setRaw("onboarding-complete", "false");
});
registerMigration(2, ({ getRaw, setRaw, removeRaw }) => {
const raw = getRaw("legacy-key");
if (raw) {
setRaw("new-key", raw);
removeRaw("legacy-key");
}
});
migrateToLatest(StorageScope.Disk);
- Versions must be positive integers, registered in any order, applied ascending
- Version state is tracked per scope via
__nitro_storage_migration_version__
- Duplicate versions throw at registration time
MMKV Migration
Drop-in helper for migrating from react-native-mmkv.
import { migrateFromMMKV } from "react-native-nitro-storage";
import { MMKV } from "react-native-mmkv";
const mmkv = new MMKV();
const migrated = migrateFromMMKV(mmkv, myStorageItem, true);
- Read priority:
getString → getNumber → getBoolean
- Uses
item.set() so validation still applies
- Only deletes from MMKV when migration succeeds
Raw String API
For cases where you want to bypass createStorageItem serialization entirely and work with raw key/value strings:
import { storage, StorageScope } from "react-native-nitro-storage";
storage.setString("raw-key", "raw-value", StorageScope.Disk);
const value = storage.getString("raw-key", StorageScope.Disk);
storage.deleteString("raw-key", StorageScope.Disk);
These are synchronous and go directly to the native backend without any serialize/deserialize step.
isKeychainLockedError(err)
Utility to detect iOS Keychain locked errors and Android key invalidation errors in secure storage operations. Returns true if the error was caused by a locked keychain (device locked, first unlock not yet performed, etc.) or an Android KeyPermanentlyInvalidatedException / InvalidKeyException. Always returns false on web.
import { isKeychainLockedError } from "react-native-nitro-storage";
try {
secureItem.get();
} catch (err) {
if (isKeychainLockedError(err)) {
}
}
Enums
AccessControl
Controls keychain item access requirements (iOS Keychain / Android Keystore). No-op on web.
enum AccessControl {
WhenUnlocked = 0,
AfterFirstUnlock = 1,
WhenPasscodeSetThisDeviceOnly = 2,
WhenUnlockedThisDeviceOnly = 3,
AfterFirstUnlockThisDeviceOnly = 4,
}
BiometricLevel
enum BiometricLevel {
None = 0,
BiometryOrPasscode = 1,
BiometryOnly = 2,
}
Use Cases
Persisted User Preferences
type UserPreferences = {
theme: "light" | "dark" | "system";
language: string;
notifications: boolean;
};
const prefsItem = createStorageItem<UserPreferences>({
key: "prefs",
scope: StorageScope.Disk,
defaultValue: { theme: "system", language: "en", notifications: true },
});
const [theme, setPrefs] = useStorageSelector(prefsItem, (p) => p.theme);
Auth Token Management
const auth = createSecureAuthStorage(
{
accessToken: { ttlMs: 15 * 60_000, biometric: true },
refreshToken: { ttlMs: 7 * 24 * 60 * 60_000 },
idToken: {},
},
{ namespace: "myapp-auth" },
);
auth.accessToken.set(response.accessToken);
auth.refreshToken.set(response.refreshToken);
auth.idToken.set(response.idToken);
if (auth.accessToken.has()) {
const token = auth.accessToken.get();
} else {
}
storage.clearNamespace("myapp-auth", StorageScope.Secure);
Feature Flags with Validation
type FeatureFlags = {
darkMode: boolean;
betaFeature: boolean;
maxUploadMb: number;
};
const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null;
const isFeatureFlags = (value: unknown): value is FeatureFlags => {
if (!isRecord(value)) return false;
return (
typeof value.darkMode === "boolean" &&
typeof value.betaFeature === "boolean" &&
typeof value.maxUploadMb === "number"
);
};
const flagsItem = createStorageItem<FeatureFlags>({
key: "feature-flags",
scope: StorageScope.Disk,
defaultValue: { darkMode: false, betaFeature: false, maxUploadMb: 10 },
validate: isFeatureFlags,
onValidationError: () => ({
darkMode: false,
betaFeature: false,
maxUploadMb: 10,
}),
expiration: { ttlMs: 60 * 60_000 },
onExpired: () => fetchAndStoreFlags(),
});
Biometric-protected Secrets
import {
AccessControl,
BiometricLevel,
createStorageItem,
StorageScope,
} from "react-native-nitro-storage";
const paymentPin = createStorageItem<string>({
key: "payment-pin",
scope: StorageScope.Secure,
defaultValue: "",
biometricLevel: BiometricLevel.BiometryOnly,
accessControl: AccessControl.WhenPasscodeSetThisDeviceOnly,
});
paymentPin.set("4829");
const pin = paymentPin.get();
paymentPin.delete();
Multi-Tenant / Namespaced Storage
function createUserStorage(userId: string) {
return {
cart: createStorageItem<string[]>({
key: "cart",
scope: StorageScope.Disk,
defaultValue: [],
namespace: `user-${userId}`,
}),
draft: createStorageItem<string>({
key: "draft",
scope: StorageScope.Disk,
defaultValue: "",
namespace: `user-${userId}`,
}),
};
}
storage.clearNamespace("user-123", StorageScope.Disk);
OTP / Temporary Codes
const otpItem = createStorageItem<string>({
key: "otp-code",
scope: StorageScope.Secure,
defaultValue: "",
expiration: { ttlMs: 5 * 60_000 },
onExpired: (key) => {
console.log(`${key} expired — prompt user to request a new code`);
},
});
otpItem.set("482917");
const code = otpItem.get();
Bulk Bootstrap with Batch APIs
import {
createStorageItem,
getBatch,
removeBatch,
setBatch,
StorageScope,
} from "react-native-nitro-storage";
const firstName = createStorageItem({
key: "first-name",
scope: StorageScope.Disk,
defaultValue: "",
});
const lastName = createStorageItem({
key: "last-name",
scope: StorageScope.Disk,
defaultValue: "",
});
setBatch(
[
{ item: firstName, value: "Ada" },
{ item: lastName, value: "Lovelace" },
],
StorageScope.Disk,
);
const [first, last] = getBatch([firstName, lastName], StorageScope.Disk);
removeBatch([firstName, lastName], StorageScope.Disk);
Atomic Balance Transfer
const fromBalance = createStorageItem({
key: "from",
scope: StorageScope.Disk,
defaultValue: 100,
});
const toBalance = createStorageItem({
key: "to",
scope: StorageScope.Disk,
defaultValue: 0,
});
function transfer(amount: number) {
runTransaction(StorageScope.Disk, (tx) => {
const from = tx.getItem(fromBalance);
if (from < amount) throw new Error("Insufficient funds");
tx.setItem(fromBalance, from - amount);
tx.setItem(toBalance, tx.getItem(toBalance) + amount);
});
}
Custom Binary Codec
const compactItem = createStorageItem<{ id: number; active: boolean }>({
key: "compact",
scope: StorageScope.Disk,
defaultValue: { id: 0, active: false },
serialize: (v) => `${v.id}|${v.active ? "1" : "0"}`,
deserialize: (v) => {
const [id, flag] = v.split("|");
return { id: Number(id), active: flag === "1" };
},
});
Coalesced Secure Writes with Deterministic Flush
import {
createStorageItem,
storage,
StorageScope,
} from "react-native-nitro-storage";
const sessionToken = createStorageItem<string>({
key: "session-token",
scope: StorageScope.Secure,
defaultValue: "",
coalesceSecureWrites: true,
});
sessionToken.set("token-v1");
sessionToken.set("token-v2");
storage.flushSecureWrites();
Bulk Data Import
Load server-fetched data into storage in one atomic call. All keys become visible simultaneously before any listener fires.
import { storage, StorageScope } from "react-native-nitro-storage";
const serverData = await fetchInitialData();
storage.import(serverData, StorageScope.Disk);
const value = storage.has("remote-config", StorageScope.Disk);
storage.import writes raw string values directly — serialization is bypassed. Use it for bootstrapping data that was already serialized by the server or exported via storage.getAll.
Storage Snapshots and Cleanup
import { storage, StorageScope } from "react-native-nitro-storage";
const diskKeys = storage.getAllKeys(StorageScope.Disk);
const diskValues = storage.getAll(StorageScope.Disk);
const secureCount = storage.size(StorageScope.Secure);
if (storage.has("legacy-flag", StorageScope.Disk)) {
storage.clearNamespace("legacy", StorageScope.Disk);
}
storage.clearBiometric();
Prefix Queries and Namespace Inspection
import { storage, StorageScope } from "react-native-nitro-storage";
const userKeys = storage.getKeysByPrefix("user-42:", StorageScope.Disk);
const userRawEntries = storage.getByPrefix("user-42:", StorageScope.Disk);
console.log(userKeys);
console.log(userRawEntries);
Optimistic Versioned Writes
import { createStorageItem, StorageScope } from "react-native-nitro-storage";
const profileItem = createStorageItem({
key: "profile",
scope: StorageScope.Disk,
defaultValue: { name: "Guest" },
});
const snapshot = profileItem.getWithVersion();
const didWrite = profileItem.setIfVersion(snapshot.version, {
...snapshot.value,
name: "Ada",
});
if (!didWrite) {
}
Storage Metrics Instrumentation
import { storage } from "react-native-nitro-storage";
storage.setMetricsObserver((event) => {
console.log(
`[nitro-storage] ${event.operation} scope=${event.scope} duration=${event.durationMs}ms keys=${event.keysCount}`,
);
});
const metrics = storage.getMetricsSnapshot();
console.log(metrics["item:get"]?.avgDurationMs);
storage.resetMetrics();
storage.setMetricsObserver(undefined);
Low-level Subscription (outside React)
import { createStorageItem, StorageScope } from "react-native-nitro-storage";
const notificationsItem = createStorageItem<boolean>({
key: "notifications-enabled",
scope: StorageScope.Disk,
defaultValue: true,
});
const unsubscribe = notificationsItem.subscribe(() => {
console.log("notifications changed:", notificationsItem.get());
});
notificationsItem.set(false);
unsubscribe();
Migrating From MMKV
import { MMKV } from "react-native-mmkv";
const mmkv = new MMKV();
const usernameItem = createStorageItem({
key: "username",
scope: StorageScope.Disk,
defaultValue: "",
});
migrateFromMMKV(mmkv, usernameItem, true);
Exported Types
import type {
Storage,
StorageItemConfig,
StorageItem,
StorageBatchSetItem,
Validator,
ExpirationConfig,
MigrationContext,
Migration,
TransactionContext,
StorageVersion,
VersionedValue,
StorageMetricsEvent,
StorageMetricsObserver,
StorageMetricSummary,
WebSecureStorageBackend,
MMKVLike,
SecureAuthStorageConfig,
} from "react-native-nitro-storage";
Dev Commands
From repository root:
bun run test -- --filter=react-native-nitro-storage
bun run lint -- --filter=react-native-nitro-storage
bun run format:check -- --filter=react-native-nitro-storage
bun run typecheck -- --filter=react-native-nitro-storage
bun run test:types -- --filter=react-native-nitro-storage
bun run test:cpp -- --filter=react-native-nitro-storage
bun run build -- --filter=react-native-nitro-storage
Inside packages/react-native-nitro-storage:
bun run test
bun run test:coverage
bun run lint
bun run format:check
bun run typecheck
bun run test:types
bun run test:cpp
bun run check:pack
bun run build
bun run benchmark
License
MIT