When building a house hunting app in React Native, one of the first architectural decisions you'll face is: Where do I store my data? Should you use SQLite for its query power, AsyncStorage for simplicity, or MMKV for blazing speed?
Let me break down each option so you can make an informed choice.
The Three Contenders
1. AsyncStorage – The Simple Classic
What is it?
AsyncStorage is React Native's built-in key-value storage system. It's asynchronous, simple, and gets the job done for basic data persistence.
Pros:
- ✅ Easy to use – Minimal setup, straightforward API
- ✅ Built into React Native – No extra dependencies (well, needs
@react-native-async-storage/async-storage
now) - ✅ Perfect for beginners – Great learning curve
- ✅ Good for small datasets – Settings, user preferences, simple lists
Cons:
- ❌ Slow performance – Asynchronous operations can add latency
- ❌ Size limitations – 6MB limit on Android (configurable but requires native changes)
- ❌ No encryption – Data is stored in plain text
- ❌ No complex queries – Just key-value pairs, no filtering or sorting
- ❌ Async-only – Everything requires
await
, which can be cumbersome
Best for:
- Small apps with limited data
- User settings and preferences
- Simple lists (< 100 items)
- Prototypes and MVPs
Code Sample:
import AsyncStorage from '@react-native-async-storage/async-storage';
// Save houses
const saveHouses = async (houses: House[]) => {
await AsyncStorage.setItem('houses', JSON.stringify(houses));
};
// Load houses
const loadHouses = async () => {
const data = await AsyncStorage.getItem('houses');
return data ? JSON.parse(data) : [];
};
2. MMKV – The Performance Champion 🏆
What is it?
MMKV is a lightning-fast key-value storage library developed by WeChat. It uses memory-mapped files and is up to 30x faster than AsyncStorage.
Pros:
- ✅ Extremely fast – Synchronous operations, instant reads/writes
- ✅ Built-in encryption – Add security with one line of code
- ✅ No size limits – Can handle much larger datasets
- ✅ Synchronous API – No
await
needed, simpler code - ✅ Type-safe methods –
getString()
,getNumber()
,getBoolean()
- ✅ Better than AsyncStorage – Drop-in replacement with superior performance
- ✅ Cross-platform – Works on iOS, Android, and even Windows
Cons:
- ❌ Still key-value – No complex queries (like SQLite)
- ❌ Requires installation – Extra dependency (~200KB)
- ❌ Not ideal for relational data – If you need JOIN operations, look elsewhere
Best for:
- Most React Native apps – This is the sweet spot!
- House hunting apps with 20-500 listings
- Apps needing frequent read/write operations
- Apps requiring data encryption
- Replacing AsyncStorage for better performance
Simple MMKV Usage
Basic Setup & Usage
// Install first:
// npx expo install react-native-mmkv
import { MMKV } from 'react-native-mmkv';
// 1. Create storage instance (do this once, at the top of your file)
const storage = new MMKV();
// 2. Save data - that's it! No await needed
const houses = [
{ id: '1', title: 'Modern Loft', price: '$2,300' },
{ id: '2', title: 'Cozy Bungalow', price: '$1,850' }
];
storage.set('houses', JSON.stringify(houses));
// 3. Load data - instant!
const savedData = storage.getString('houses');
const myHouses = savedData ? JSON.parse(savedData) : [];
// 4. Delete data
storage.delete('houses');
Simple Context Version (Minimal)
// contexts/HousesContext.tsx
import React, { createContext, useContext, useState, useEffect } from 'react';
import { MMKV } from 'react-native-mmkv';
const storage = new MMKV();
const HousesContext = createContext();
export function HousesProvider({ children }) {
const [houses, setHouses] = useState([]);
// Load on start
useEffect(() => {
const data = storage.getString('houses');
if (data) setHouses(JSON.parse(data));
}, []);
// Add house
const addHouse = (house) => {
const newHouse = { ...house, id: Date.now().toString() };
const updated = [...houses, newHouse];
storage.set('houses', JSON.stringify(updated));
setHouses(updated);
};
// Delete house
const deleteHouse = (id) => {
const updated = houses.filter(h => h.id !== id);
storage.set('houses', JSON.stringify(updated));
setHouses(updated);
};
return (
<HousesContext.Provider value={{ houses, addHouse, deleteHouse }}>
{children}
</HousesContext.Provider>
);
}
export const useHouses = () => useContext(HousesContext);
Using it in Your Components
// In any component
import { useHouses } from '@/contexts/HousesContext';
export default function Houses() {
const { houses, addHouse, deleteHouse } = useHouses();
return (
<FlatList
data={houses}
renderItem={({ item }) => (
<View>
<Text>{item.title}</Text>
<Button title="Delete" onPress={() => deleteHouse(item.id)} />
</View>
)}
/>
);
}
Key Differences from AsyncStorage
// ❌ AsyncStorage (slower, needs await)
await AsyncStorage.setItem('houses', JSON.stringify(houses));
const data = await AsyncStorage.getItem('houses');
// ✅ MMKV (faster, synchronous)
storage.set('houses', JSON.stringify(houses));
const data = storage.getString('houses');
Advanced MMKV Features
// Multiple storage instances
const userStorage = new MMKV({ id: 'user-data' });
const cacheStorage = new MMKV({ id: 'cache' });
// Encryption
const secureStorage = new MMKV({
id: 'secure-data',
encryptionKey: 'my-encryption-key'
});
// Direct type methods (no JSON parsing needed!)
storage.set('viewCount', 42);
storage.set('isLoggedIn', true);
const count = storage.getNumber('viewCount'); // Returns number
const loggedIn = storage.getBoolean('isLoggedIn'); // Returns boolean
// Delete specific key
storage.delete('houses');
// Clear all data
storage.clearAll();
// Get all keys
const keys = storage.getAllKeys();
3. SQLite – The Power User's Choice
What is it?
SQLite is a full-featured relational database that runs locally on the device. It's powerful, battle-tested, and perfect for complex data relationships.
Pros:
- ✅ Complex queries – JOIN, WHERE, ORDER BY, GROUP BY, etc.
- ✅ Relational data – Perfect for normalized data structures
- ✅ Indexing – Fast lookups on specific fields
- ✅ Transactions – ACID compliance for data integrity
- ✅ Large datasets – Can handle thousands of records efficiently
- ✅ SQL power – Full database capabilities
Cons:
- ❌ Complex setup – Requires SQL knowledge
- ❌ More boilerplate – Schema definitions, migrations, queries
- ❌ Overkill for simple apps – Too much complexity for basic CRUD
- ❌ Harder to debug – SQL errors can be cryptic
- ❌ Larger bundle size – Adds ~1-2MB to your app
Best for:
- Apps with complex data relationships (houses → viewings → notes → documents)
- Advanced filtering and searching (e.g., "3+ bedrooms, under $2000, within 5 miles")
- Apps with 1000+ records
- Data that needs transactions (banking, inventory)
- Apps requiring offline-first with complex sync logic
Code Sample:
import * as SQLite from 'expo-sqlite';
const db = SQLite.openDatabase('househunt.db');
// Create table
db.transaction(tx => {
tx.executeSql(
`CREATE TABLE IF NOT EXISTS houses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
price TEXT,
location TEXT,
bedrooms INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);`
);
});
// Insert house
const addHouse = (house: House) => {
db.transaction(tx => {
tx.executeSql(
'INSERT INTO houses (title, price, location, bedrooms) VALUES (?, ?, ?, ?)',
[house.title, house.price, house.location, house.bedrooms]
);
});
};
// Complex query
const searchHouses = (minBedrooms: number, maxPrice: number) => {
db.transaction(tx => {
tx.executeSql(
'SELECT * FROM houses WHERE bedrooms >= ? AND price <= ? ORDER BY price ASC',
[minBedrooms, maxPrice],
(_, { rows }) => console.log(rows._array)
);
});
};
Decision Matrix: Which Should You Choose?
Scenario | Recommendation | Why |
---|---|---|
Simple house list (< 50 houses) | MMKV | Fast, simple, encrypts |
Medium-size app (50-500 houses) | MMKV | Best balance of speed/simplicity |
Complex filtering ("3BR, < $2k, near work") | SQLite | Need SQL query power |
Just user preferences/settings | MMKV or AsyncStorage | Either works, MMKV is faster |
Large dataset (1000+ houses) | SQLite | Better performance at scale |
Relational data (houses + viewings + notes) | SQLite | Need JOIN operations |
Need encryption | MMKV or SQLite | Both support encryption |
Prototyping quickly | MMKV | Fastest to implement |
Top comments (0)