Mobile Storage & Memory

Understand on-device storage (key-value, SecureStore, SQLite, files), offline-first design, and app memory so your AI-built app is fast, private and does not crash.

Phones have two kinds of memory that beginners mix up. Storage is what survives after the app closes (files, databases, preferences). Memory (RAM) is what the running app uses and the OS can take back at any time. Good apps use each for the right job.

Core concepts

  1. Key-value storage: AsyncStorage and MMKV save small values like settings and flags. MMKV is much faster and synchronous but needs a development build. — AsyncStorage
  2. Secure storage: Tokens and secrets go in the platform keychain/keystore through expo-secure-store, never in AsyncStorage or plain files. — Expo SecureStore
  3. On-device SQLite: expo-sqlite gives a real relational database on the phone for structured, queryable offline data such as notes, workouts or inventory. — Expo SQLite
  4. Files and media: Store large files in the app's document or cache directory, keep only paths in your database, and clean the cache when it grows. — Expo FileSystem
  5. Offline-first design: Read from local storage first, write locally, then sync with the server in the background and resolve conflicts with a clear rule (last write wins, or merge). — Expo local-first
  6. App memory (RAM): Large images, unbounded lists and leaked listeners increase memory use until the OS kills the app. Virtualise lists, resize images and clean up effects. — React Native performance
  7. Hermes and profiling: Expo apps use the Hermes engine. Profile with React Native DevTools, Xcode Instruments and Android Studio's profiler to find slow renders and memory growth. — Hermes

Concept videos

YouTube channels and searches for these topics. On a large screen they open in the reading panel next to the roadmap.

Explanation

Choosing the right store

Preferences and flags go in key-value storage. Secrets go in SecureStore. Anything you filter, sort or join goes in SQLite. Big binary data goes on the file system with only its path stored in a database.

Why memory bugs show up late

Memory problems appear after minutes of use or on low-end phones, so simulators on a fast laptop hide them. Test long sessions on a mid-range Android device.

Sync is the hard part

Local-first is easy until the same record is edited on two devices. Decide the conflict rule early and write it in the spec so the agent implements it deliberately.

What Is It?

Storage persists data across launches; memory is the working space of the running app. Offline-first apps treat the phone's database as the primary source and sync in the background.

Why Should I Care?

Fast startup, offline use and privacy all depend on choosing the right store, and crashes from memory pressure are a common reason for bad reviews.

Real World Analogy

Storage is your filing cabinet at home; memory is the desk you work on. The desk is small and gets cleared when someone needs the room, so anything important must be filed.

Visual Mental Model

text
Secrets      -> SecureStore (keychain)
Preferences  -> MMKV / AsyncStorage
Structured   -> SQLite (+ sync to server)
Big files    -> FileSystem (path in DB)
Running data -> RAM (keep it small)

Beginner Explanation

Put settings in key-value storage, tokens in SecureStore and your main data in SQLite, then ask the agent to make the app work in airplane mode.

Smallest Possible Example

ts
import * as SecureStore from 'expo-secure-store';

export async function saveToken(token: string) {
  await SecureStore.setItemAsync('access_token', token);
}

export async function loadToken() {
  return SecureStore.getItemAsync('access_token');
}

Common Mistakes

❌ Saving access tokens in AsyncStorage.

It is unencrypted storage; use SecureStore.

❌ Loading entire tables into memory.

Page queries and virtualise lists.

❌ Never testing offline.

Many apps break the moment the network drops; test airplane mode.

Real Project Example

Note, task and fitness apps commonly keep data in SQLite on the device and sync later; Expo documents local-first patterns for this.

Build This Mini Project

Build a notes app that stores notes in expo-sqlite, saves a theme flag in key-value storage, and works fully in airplane mode.

Interview Question

Where should an access token be stored on a phone, and why?

In the platform secure store (Keychain/Keystore via SecureStore) because it is encrypted and protected by the OS, unlike plain storage that other tools or backups can read.

Key Takeaways

  • Match data type to storage type.
  • Secrets only in SecureStore.
  • Design for offline and decide conflict rules early.
  • Watch RAM: virtualise lists and clean up effects.

Stack for this step

LayerPickWhy
PreferencesMMKV / AsyncStorageSmall values; MMKV needs a dev build.
Secretsexpo-secure-storeKeychain and Keystore.
Structured dataexpo-sqliteRelational offline data.
Filesexpo-file-systemDocuments and cache.

Prompts for Cursor, Claude Code & Codex

Paste these into Cursor, Claude Code, Codex, or any coding agent. Replace the bracketed parts with your app details, and keep the agent in plan mode first so you review the approach before it edits files.

Storage plan

text
From SPEC.md, list every piece of persisted data and choose: SecureStore, MMKV/AsyncStorage, SQLite or file system. Give a one-line reason each and flag anything sensitive. Output a table.

Offline-first notes

text
Implement a local-first notes feature with expo-sqlite: schema, migrations table, CRUD helpers in lib/db.ts, and a hook that reads from SQLite. Add a syncedAt column for later server sync. Do not add a network layer yet.

Memory audit

text
Audit the app for memory risks: unbounded lists, large images without resizing, listeners or timers without cleanup, and global caches. List each with file and line and a fix.

Claude Code skill for this step

Save this as .claude/skills/choose-storage/SKILL.md in your project so Claude Code loads it automatically when the task matches. The same text works as a Cursor rule or an AGENTS.md section.

text
---
name: choose-storage
description: Use when adding any persisted data to the app, to select the right storage and avoid leaking secrets.
---
1. Classify the data: secret, preference, structured, or file.
2. Use SecureStore for secrets, key-value for preferences, SQLite for structured data, FileSystem for large files.
3. Add a migration or version when changing a persisted shape.
4. Test cold start and airplane mode before finishing.

Rules, databases & blogs to use

Resources

The 60-second story

At home you keep important papers in a filing cabinet, a few daily things in a drawer, valuables in a safe, and photos in boxes. On your desk you only keep what you are using right now, because the desk is small and someone might clear it.

A phone app is the same. The safe is SecureStore, the drawer is key-value storage, the cabinet is SQLite, the boxes are files, and the desk is RAM. When the OS needs space it clears your desk without asking, so anything you cannot afford to lose has to be filed first.

Mental model: file it before you need it, and keep the desk light.

Threads in the same domain as this chapter — go deeper on iHateReading without leaving the roadmap.

Vector search using vector embeddings cover

Vector search using vector embeddings

Embeddings, similarity search, and RAG-shaped memory for apps.

Agent harnessing: the part of building AI agents nobody talks about cover

Agent harnessing: the part of building AI agents nobody talks about

Loop, tools, memory, sandbox, and tracing live in your code — not the model weights.

Firebase, Supabase and Clerk authentication cover

Firebase, Supabase and Clerk authentication

Auth options for apps compared.