Choosing the right caching tool is crucial for building performant applications. Different tools serve different purposes: server-side caching for cross-user data, client-side caching for per-user sessions, and embedded databases for reactive UI updates. This article explores popular caching tools and when to use each one.
Redis
Redis is a real in-memory data store that runs as its own server process. It stores data across requests and across users, making it ideal for server-side caching and shared state management.
Characteristics:
- Runs as a separate server process
- Stores data across requests and users
- Data persists until explicitly expired or deleted
- Networked service accessible via TCP
Use cases:
- Server-side caching to reduce database load
- Message queues and pub/sub systems
- Session storage and shared state
- Cross-request caching in distributed systems
TanStack Query (React Query)
TanStack Query, also known as React Query, runs in your app's memory and stores data per user session. It implements the proxy pattern, caching API responses to avoid redundant fetches during navigation or re-renders.
Characteristics:
- Runs in app memory, not a separate server
- Stores data per user session
- Data is ephemeral and tied to app lifetime
- Can use localStorage or sessionStorage for persistence (~5-10MB)
With React 19 + Server Components:
- Client components: Caches API results in the browser for that user session
- Server components: Only lasts for that single request, avoiding duplicate fetches within a render and enabling faster initial load
Use cases:
- Client-side caching of API calls
- Avoiding redundant fetches during navigation
- Managing loading, error, and retry states
- Automatic refetching and cache invalidation
TL;DR: Redis is server-side, cross-user, long-lived cache. TanStack Query is app-level, per-user, short-lived cache. They complement each other: Redis speeds up getting data from DB/API, while TanStack Query speeds up reusing data already fetched in the app.
TanStack DB
TanStack DB is a client-side embedded database layer that extends TanStack Query. It provides collections, live queries, and optimistic mutations for managing structured data in React applications.
Key Features:
- Collections: Local, typed sets of objects representing data (normalized tables)
- Live Queries: Reactive queries that update incrementally, often in under 1 millisecond even for large datasets
- Optimistic Mutations & Transactions: Update data locally instantly while syncing changes to the backend, with rollback capabilities
- Entirely client-side data store using in-memory structures (or optionally localStorage)
TanStack DB vs Redis
| Feature | Redis | TanStack DB |
|---|---|---|
| Location | Server-side, separate process | Client-side (in browser/app memory) |
| Persistence Scope | Multi-user, shares across sessions | Per-user session, non-persistent |
| Use Case | Cross-request caching, centralized DB | Instant UI updates, live client reactivity |
| Network Presence | Networked (TCP) service | Embedded in app—no network call |
| Best For | Backend caching, shared state | UI responsiveness, real-time local UI |
Redis belongs in your backend to cache data at the source, reduce DB load, and enable sharing across clients. TanStack DB belongs in your client app when you need highly responsive, reactive UI states with instant updates and near-zero re-render cost. You can use both together: backend uses Redis to deliver fast API responses, while client uses TanStack DB to manage data once fetched.
TanStack DB vs localStorage
| Feature | localStorage | TanStack DB |
|---|---|---|
| Speed | Synchronous read/write, not optimized for large or reactive datasets | In-memory reactive store, optimized for queries and updates in <1ms |
| Data Shape | Stores only strings—you manually serialize/deserialize JSON | Stores typed objects and collections with relationships |
| Reactivity | No built-in way to update UI when data changes—you must write listeners and state management manually | Built-in reactive live queries that automatically update components |
| Queries | No querying—you fetch entire objects/arrays and filter yourself | Indexed queries, filtering, sorting, pagination out of the box |
| Mutations | Manual overwrite of stored data | Optimistic mutations, rollbacks, transactions |
| Persistence | Survives reloads | Primarily in-memory (can persist with localStorage or IndexedDB as backing store) |
| DX (Dev Experience) | DIY—you handle all syncing, cache invalidation, and re-renders | Integrated with TanStack Query for network sync, cache, and UI updates |
When localStorage makes sense: You just need to remember small settings or simple flags across page reloads (theme=dark, rememberMe=true). No need for reactivity or complex queries.
When TanStack DB makes sense: You're managing structured data (lists of objects, relational data). You want live UI updates when data changes. You're already using TanStack Query and want local & server data to sync seamlessly. You need fast client-side queries (think 10k+ items instantly filtered and paginated).
Key takeaway: localStorage is a persistence mechanism. TanStack DB is a reactive in-memory database that can optionally use localStorage (or IndexedDB) as its persistence layer—but adds querying, reactivity, and integration with your server data.
TanStack DB vs TanStack Query
React Query (TanStack Query): Focuses on fetching and caching remote data (usually from an API). Cache shape is flat—each query has its own key + data blob. Good for keeping data fresh from a server, automatic refetching/invalidation, and dealing with network state. Not great for relating multiple datasets locally, querying/filtering large datasets without hitting the server, or working fully offline with complex relationships.
TanStack DB: Focuses on querying, joining, and relating local data, like a mini relational database. Cache shape is structured—tables, relationships, indexes. Good for joining multiple datasets in memory (e.g., users with posts with comments) without refetching, complex local queries (WHERE, JOIN, ORDER BY logic without a server), and offline-first workflows with advanced filtering/sorting. Not great for just fetching simple remote data or handling remote invalidation by itself (you still need Query or manual sync).
TanStack DB Limitations
Disadvantages:
- Very new (still in early versions)
- Not a standalone storage engine—it's an in-memory query & relation layer
- You still need a persistence layer (IndexedDB, localStorage, backend DB) if you want data to survive reloads
- Bundle size: Larger than a basic state management library (e.g., Zustand). Overhead might be unnecessary if your data model is simple
- Learning curve: Has a relational model and query system similar to SQL—great for complex data, but overkill for trivial lists. You need to think about schemas, tables, relationships, indexes
- SSR & server components: Works in React 19 server components, but SSR persistence strategies are still evolving. Without careful design, you can end up duplicating data between server and client
Best suited for: Complex client-side relationships between entities. Apps needing SQL-like queries locally. Combining multiple sources into a unified in-memory graph.
Not great for: Simple apps that just need a few useState calls or react-query. Large-scale offline-first persistence without careful tuning.
TanStack DB itself doesn't have a fixed storage limit—it's just an in-memory data layer in JavaScript. If you run it with no persistence layer, it can store as much as the browser's JavaScript heap allows. Browser JS heap limits are much larger than localStorage but still finite (often hundreds of MB; Chrome can handle ~1–2 GB on desktop, much less on mobile). Once the tab reloads, all that data is gone unless you persist it somewhere.
IndexedDB
IndexedDB is a built-in browser NoSQL database that can be used with TanStack DB as a persistence layer. In many cases, it's a better persistence layer than localStorage.
What IndexedDB Is:
- A built-in browser NoSQL database
- Can store much larger amounts of data than localStorage (hundreds of MBs vs ~5-10MB)
- Works asynchronously (non-blocking), so it doesn't freeze the main thread like localStorage can
- Stores structured data, not just strings—so no manual JSON parsing/stringifying needed
- Great for offline-first apps and caching large datasets locally
IndexedDB vs localStorage
| Feature | localStorage | IndexedDB |
|---|---|---|
| Max storage | ~5-10MB per origin | Hundreds of MBs (varies by browser) |
| Data format | Only strings | Objects, arrays, blobs |
| Performance | Synchronous, blocks main thread | Asynchronous, non-blocking |
| Best for | Small settings, flags | Large datasets, offline caching |
| TanStack DB fit | Simple, small persistence | Complex, large, and performant persistence |
localStorage Browser Limits
| Browser | Approx Limit |
|---|---|
| Chrome / Edge | ~10 MB |
| Firefox | ~10 MB |
| Safari (macOS) | ~5 MB |
| Safari (iOS) | ~5 MB |
| Opera | ~10 MB |
| IE 10+ | ~10 MB |
TanStack DB persistence: No persistence layer configured → TanStack DB = ephemeral, in-memory store. You choose a persistence adapter → TanStack DB becomes a reactive queryable layer on top of your chosen storage.
AWS ElastiCache
AWS ElastiCache is a managed caching service that allows you to use Redis as the engine. You get all Redis features (pub/sub, sorted sets, Lua scripts, streams, etc.), but you don't worry about running Redis yourself.
Benefits:
- Managed service: AWS provisions, maintains, and monitors the Redis cluster
- High availability: Automatic failover, replication, and multi-AZ deployment
- Scalability: Easy to scale up or down based on your needs
- Security: VPC integration, encryption at rest and in transit
- Monitoring: Built-in CloudWatch metrics and alerts
Without AWS: You'd spin up a VM, install Redis, configure persistence, replication, monitoring, etc. With ElastiCache for Redis: You just tell AWS "Give me a Redis cluster with 3 replicas in 2 availability zones" → AWS provisions it, keeps it healthy, replaces failed nodes, and applies patches.
AWS MemoryDB
Amazon MemoryDB for Redis is Redis-compatible but designed to be a durable primary database with multi-AZ replication and point-in-time recovery.
Key Features:
- Durability: Once the database confirms your write, the data won't be lost, even if there's a crash, node failure, or full data center outage
- Persistence to disk: Not just in-memory, data is persisted
- Multi-AZ replication: Your data is automatically copied (replicated) across multiple AWS Availability Zones for redundancy
- Point-in-time recovery: You can restore your database to the exact state it was at a specific time in the past (down to seconds or minutes)
- Snapshots and backups: Additional recovery options for data protection
MemoryDB is ideal when you need Redis compatibility but require stronger durability guarantees than traditional Redis. It's suitable for use cases where data loss is unacceptable and you need a primary database with Redis's performance characteristics.
Alternative Caching Solutions
| Library | Description | Persistence |
|---|---|---|
| RxDB | Reactive, offline-first DB for JS apps; supports multiple persistence backends | IndexedDB, WebSQL, SQLite, others |
| WatermelonDB | Optimized for large datasets in React/React Native; syncs with server | SQLite (RN) / IndexedDB (web) |
| AlaSQL | Pure JS SQL engine that runs in memory or on IndexedDB/localStorage | IndexedDB, localStorage |
| Lovefield | Google's relational DB for web apps, built on IndexedDB | IndexedDB |
These alternatives provide different approaches to client-side data management. However, if you're already using other TanStack products, TanStack Query and TanStack DB work better together due to their integrated design and shared ecosystem.
Conclusion
Choosing the right caching tool depends on your specific needs. Redis excels at server-side, cross-user caching. TanStack Query is perfect for client-side API response caching. TanStack DB provides reactive, relational data management in the browser. IndexedDB offers robust browser-based persistence for large datasets.
AWS ElastiCache simplifies Redis management in the cloud, while AWS MemoryDB provides Redis compatibility with enhanced durability. These tools complement each other: use Redis on the backend to speed up data retrieval, TanStack Query to cache API responses in the client, and TanStack DB for complex local data relationships and reactive UI updates.
Understanding the strengths and limitations of each tool helps you build efficient, scalable applications with optimal caching strategies at every layer of your stack.
