npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

expo-native-storage

v0.2.0

Published

Lightning-fast native storage for Expo.

Downloads

243

Readme

expo-native-storage

npm version npm downloads

Lightning-fast native storage for Expo using UserDefaults and SharedPreferences.

Why?

  • Fast: Direct native storage, no bridge delays
  • Tiny: 19x smaller bundle size compared to AsyncStorage
  • Scales: Gets faster with more operations (up to 32x on Android)
  • Web support: Falls back to localStorage
  • Native: Uses UserDefaults (iOS) & SharedPreferences (Android)

Installation

# bun
bunx expo install expo-native-storage
# npm
npx expo install expo-native-storage

[!IMPORTANT] After installation, you must rebuild your app to link the native module. This module requires native code and will not work with Expo Go. You need a development build or production build.

# For development builds
npx expo prebuild --clean
npx expo run:ios
# or
npx expo run:android

This module requires native code and will not work with Expo Go. You need a development build or production build.

Usage

Async API (Promise-based)

import Storage from 'expo-native-storage';

// Store strings
await Storage.setItem('username', 'john_doe');
const username = await Storage.getItem('username'); // 'john_doe'

// Store objects
await Storage.setObject('user', { 
  name: 'John', 
  age: 30,
  premium: true 
});
const user = await Storage.getObject('user');

// Remove items
await Storage.removeItem('username');

// Clear all
await Storage.clear();

Sync API (Immediate, no Promises)

import Storage from 'expo-native-storage';

// Store strings synchronously
Storage.setItemSync('username', 'john_doe');
const username = Storage.getItemSync('username'); // 'john_doe'

// Store objects synchronously
Storage.setObjectSync('user', { 
  name: 'John', 
  age: 30,
  premium: true 
});
const user = Storage.getObjectSync('user');

// Remove items synchronously
Storage.removeItemSync('username');

// Clear all synchronously
Storage.clearSync();

When to use sync vs async:

  • Sync methods: App initialization, reading config on startup, settings screens
  • Async methods: When you need to coordinate with other async operations, or prefer Promise-based code

Example: Theme Storage

// Save theme preference
await Storage.setItem('theme', 'dark');

// Load on app start
const theme = await Storage.getItem('theme') || 'light';

API

Async Methods

| Method | Description | Return | |--------|-------------|---------| | setItem(key, value) | Store a string value | Promise<void> | | getItem(key) | Get a string value | Promise<string \| null> | | setObject(key, object) | Store an object as JSON | Promise<void> | | getObject<T>(key) | Get an object from JSON | Promise<T \| null> | | removeItem(key) | Remove an item | Promise<void> | | clear() | Remove all items | Promise<void> | | multiGet(keys) | Get multiple items at once | Promise<Record<string, string \| null>> | | multiSet(items) | Set multiple items at once | Promise<void> |

Sync Methods

| Method | Description | Return | |--------|-------------|---------| | setItemSync(key, value) | Store a string value | void | | getItemSync(key) | Get a string value | string \| null | | setObjectSync(key, object) | Store an object as JSON | void | | getObjectSync<T>(key) | Get an object from JSON | T \| null | | removeItemSync(key) | Remove an item | void | | clearSync() | Remove all items | void |

Performance Results

Async Methods - Real Device Testing:

| Platform | Operations | expo-native-storage | AsyncStorage | Improvement | |----------|------------|-------------------|--------------|-------------| | Android Phone | 100 ops | 11ms | 165ms | 15x faster | | | 200 ops | ~25ms | ~290ms | 11x faster | | | 500 ops | ~50ms | ~650ms | 13x faster | | | 1000 ops | ~95ms | ~1216ms | 13x faster | | Android Emulator | 100 ops | 12ms | 219ms | 18x faster | | iOS Phone | 100 ops | 72ms | 72ms | Same speed | | Bundle Size | - | 19.6KB | 381KB | 19x smaller |

Sync Methods - Real Device Testing:

| Platform | Operations | Sync Methods | Async Methods | Improvement | |----------|------------|--------------|---------------|-------------| | Android Phone | 1000 ops | 98ms | 472ms | 4.8x faster | | iOS Phone | 1000 ops | 1098ms | 1499ms | 1.4x faster |

Note on iOS Performance: iOS sync methods are limited by UserDefaults disk I/O (~1ms per write). For bulk operations (1000+ writes), consider using specialized libraries like react-native-mmkv. Sync methods are perfect for typical use cases like app settings and user preferences.

Tested on iPhone 17 Pro and Nothing Phone 3a with Android 15.
Emulator results from MacBook Pro M4 with 16GB RAM.

Performance at Scale

The performance advantage of expo-native-storage increases with usage:

Why? SharedPreferences uses in-memory caching after first access, while AsyncStorage hits the SQLite database for every operation. The more operations you perform, the bigger the performance gap becomes.

Perfect for:

  • Settings screens with many preferences
  • Offline data caching with frequent reads
  • State persistence with frequent updates
  • User session data with multiple keys

Migration from AsyncStorage

// Before (AsyncStorage)
import AsyncStorage from '@react-native-async-storage/async-storage';
await AsyncStorage.setItem('key', 'value');

// After (expo-native-storage)
import Storage from 'expo-native-storage';
await Storage.setItem('key', 'value');

Drop-in replacement with zero breaking changes.

Platform Notes

  • iOS: Uses UserDefaults (synchronous, limited to ~1MB per key)
  • Android: Uses SharedPreferences (synchronous, good for small data)
  • Web: Uses localStorage (synchronous, ~5-10MB limit)

Requirements

  • Expo SDK 50+
  • Development builds (not available in Expo Go)

Troubleshooting

Error: Cannot find native module 'ExpoNativeStorage'

This error means the native module isn't linked. To fix:

  1. Rebuild your app after installing:

    bunx expo prebuild --clean
    bunx expo run:ios  # or run:android
  2. Clear caches if the issue persists:

    # clear Metro bundler cache
    bunx expo start -c
       
    # clear all caches
    rm -rf node_modules
    bun install  # or npm install
    bunx expo prebuild --clean
  3. Verify installation:

    • Check that expo-native-storage is in your package.json
    • Make sure you're using a development build, not Expo Go
    • For iOS: Check that ExpoNativeStorage appears in your Podfile.lock
    • For Android: Check that the module is in your build.gradle dependencies

Still having issues?

Open an issue on GitHub with:

  • Your Expo SDK version
  • React Native version
  • Platform (iOS/Android)
  • Full error message
  • Whether you're using Expo Go or a development build

License

MIT