RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Dev Tools
Dev Tools/2026-03-29Intermediate

Local Data Persistence in Rork Apps — Choosing AsyncStorage, MMKV, and SQLite by Measurement

A measured comparison of local storage in Rork apps: AsyncStorage, MMKV, and SQLite. Covers a zero-downtime migration, MMKV pitfalls, and how transactions plus WAL make SQLite bulk inserts dozens of times faster — grounded in hands-on indie development.

Rork515AsyncStorage10MMKV6SQLite2Local StorageData Persistence2React Native209

Premium Article

The night a list screen froze for a moment

I had added a favorites feature to one of the apps I run as an indie developer. Everything worked smoothly up to a few hundred entries. Then a heavy user's favorites grew into the thousands, and reports came in: every time they opened the list, the screen flashed white for a beat.

The cause was that, on launch, the app loaded the entire favorites list from AsyncStorage and ran JSON.parse on one enormous array every single time. The data was just key-value, yet startup got heavier as the data grew. Back then I had told myself "storage is something I can figure out later," and that complacency came back to me as a visible drop in perceived speed.

Local storage choices don't matter while an app is small — anything works. The difference shows up once a user's data has grown. That's exactly why understanding the mechanics up front saves you from rebuilding later.

This guide compares the three staples available in React Native / Expo-based Rork apps — AsyncStorage, MMKV, and SQLite — and goes deeper than a feature tour: into why speed appears or doesn't, how to migrate safely, the pitfalls to avoid, and how to turn a "slow SQLite" into a fast one. All of it is grounded in things I actually tripped over.

AsyncStorage — The Shortest Path to Something That Works

AsyncStorage is the community-maintained key-value store for React Native. It works out of the box in projects Rork generates, and its learning curve is close to zero.

  • Data format: String key-value pairs (objects via JSON.stringify)
  • API: Fully Promise-based and asynchronous
  • Backend: SQLite on Android (6MB default cap), plist files on iOS
  • Thread safety: Internally serialized, safe under concurrent access
import AsyncStorage from '@react-native-async-storage/async-storage';
 
// Save user preferences
const saveUserPreferences = async (preferences: {
  theme: 'light' | 'dark';
  language: string;
  notifications: boolean;
}) => {
  try {
    const jsonValue = JSON.stringify(preferences);
    await AsyncStorage.setItem('@user_preferences', jsonValue);
    console.log('Preferences saved successfully');
  } catch (error) {
    console.error('Failed to save preferences:', error);
  }
};
 
// Load user preferences
const loadUserPreferences = async () => {
  try {
    const jsonValue = await AsyncStorage.getItem('@user_preferences');
    if (jsonValue !== null) {
      return JSON.parse(jsonValue);
    }
    return { theme: 'light', language: 'en', notifications: true };
  } catch (error) {
    console.error('Failed to load preferences:', error);
    return null;
  }
};
 
// Expected output:
// saveUserPreferences({ theme: 'dark', language: 'en', notifications: true })
// => "Preferences saved successfully"
// loadUserPreferences()
// => { theme: 'dark', language: 'en', notifications: true }

For settings, flags, temporary token storage, a few dozen cached entries, and MVP-stage apps, this is plenty. I personally spend the first few weeks of a new app almost entirely on AsyncStorage — in the phase where I want fast iteration, I'd rather not sink time into storage design.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Why AsyncStorage slows down as data grows, plus a one-time migration to MMKV with no data loss
Making SQLite bulk inserts dozens of times faster with transactions and WAL, with measured behavior
A quick decision flow to pick AsyncStorage / MMKV / SQLite from the nature of your data
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Dev Tools2026-05-19
Fixing 'Row too big to fit into CursorWindow' on Android When AsyncStorage Holds Too Much in Rork
When a React Native app generated with Rork stores large JSON or image metadata in AsyncStorage, Android can throw a Row too big to fit into CursorWindow exception. Here are the practical fixes — MMKV migration, chunked keys, payload trimming, and compression — explained from real wallpaper-app experience.
Dev Tools2026-04-20
Rork App Data Not Saving or Disappearing: Causes and Fixes
When Rork app data isn't saving or disappears after a restart, a handful of root causes explain most cases. This guide covers AsyncStorage pitfalls, async timing bugs, key mismatches, and when to switch to MMKV.
Dev Tools2026-06-22
When a Poisoned Cache Crashes Your App on Every Launch — Designing a Safe-Mode Boot Your Users Can Escape On Their Own
When a persisted cache goes bad and the app crashes at the same spot on every launch, the only option left to the user is to reinstall. This article designs a safe-mode boot for Expo (React Native): the app counts its own early crashes, confirms a launch only once it becomes interactive, and resets just the dangerous state in graduated steps.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →