Why Caching Is Critical for Mobile
Caching stores frequently accessed data closer to where it is needed, reducing network requests, lowering latency, and enabling offline functionality. For mobile apps, effective caching is the difference between an app that feels instant and one that shows loading spinners on every interaction.
The Three Layers of Mobile Caching
1. HTTP Cache (Network Layer)
HTTP caching uses standard headers to tell clients and intermediaries how to cache responses.
Cache-Control Header:
- public - Response can be cached by any cache (CDN, browser, app)
- private - Only the client should cache it
- max-age=3600 - Cache is valid for 3600 seconds
- no-cache - Cache but revalidate before using
- no-store - Never cache (use for sensitive data)
- stale-while-revalidate=300 - Serve stale cache while fetching fresh data in background
ETag and Last-Modified:
Conditional requests let the server tell the client whether cached data is still fresh. Client sends If-None-Match or If-Modified-Since. Server returns 304 Not Modified (no body) if unchanged. This saves bandwidth while ensuring freshness.
| Content Type | Recommended Cache-Control |
|---|---|
| Static images (versioned) | public, max-age=31536000, immutable |
| User avatar | public, max-age=86400 |
| API list endpoint | private, max-age=60, stale-while-revalidate=300 |
| Auth tokens | no-store |
2. Server-Side Cache
Server-side caching reduces database load and speeds up API responses. Redis is the most common choice with sub-millisecond reads, TTL support, and complex data structures.
Common Patterns:
- Cache-Aside - Check cache first. If miss, fetch from database, store in cache, return. Most common pattern.
- Write-Through - Write to cache and database simultaneously. Always fresh but adds write latency.
- Write-Behind - Write to cache immediately, async write to database. Lowest latency but risk of data loss.
Cache frequently read, rarely changing data (categories, settings, feature flags), expensive computations (leaderboard rankings), and external API responses.
3. Client-Side Cache (App Layer)
In-Memory Cache: Fastest access, lost when app terminates. Use for data needed within a single session.
Persistent Cache: Survives app restarts. SQLite/Room/Core Data for structured data. MMKV for ultra-fast key-value storage (10x faster than AsyncStorage). File system for images and large blobs.
Image Caching: Use dedicated libraries (SDWebImage for iOS, Coil/Glide for Android, FastImage for React Native). Set maximum disk cache size of 100-500 MB.
Cache Invalidation
Time-Based (TTL)
Set an expiration on every cached item. Short TTL (30-60 seconds) for frequently changing data, medium TTL (5-30 minutes) for moderate changes, long TTL (1-24 hours) for rarely changing data.
Event-Based
Invalidate when underlying data changes. User updates profile, invalidate profile cache. New item added, invalidate list cache.
Version-Based
Include a version in cache keys (user_profile_v3_123). When data format changes, increment the version. Old entries expire naturally.
Offline-First Architecture
For apps that must work without internet:
- Read from local cache first (instant UI)
- Fetch from server in the background
- Update local cache with fresh data
- Queue write operations that occurred offline
- Sync queued writes when connectivity returns
Cache Size Management
Implement eviction policies: LRU (remove least recently used), size-based (evict when exceeding threshold), or age-based (remove items older than a certain age). Monitor disk usage in production.
Measuring Cache Effectiveness
- Cache hit ratio - Aim for 80%+
- Cache miss latency - Compare with cache hit latency
- Cache size over time - Ensure it stays within bounds