In 2024, "how do I fetch data in React" still has three serious answers: TanStack Query (formerly React Query), SWR, RTK Query. Three philosophies. Here is how we apply them.
TanStack Query 5
Our default on 90% of React projects. The queryKey + queryFn pattern is simple, devtools are killer, mutations with onSuccess/onError match how we think about forms. v5 brought stable suspense-mode and much better types.
SWR
Lighter, less opinionated, perfect for apps where fetching is simple (list + detail + a few mutations). For us it is the pick on small projects or when there is already a Vercel-centric stack (Next.js + SWR is excellent).
RTK Query
Part of Redux Toolkit. Its strength is when the app already uses Redux for other reasons: bringing in another client would be redundant. For new apps we avoid Redux as default — the bundle and complexity are not justified in most cases.
Decision matrix
| Case | Pick |
|---|---|
| New app, complex fetching, many forms | TanStack Query |
| Simple Next.js site, few endpoints | SWR (or nothing — Server Actions are enough) |
| Legacy enterprise app with Redux | RTK Query |
| Strict offline-first app | TanStack Query + persister |
Patterns we always use
- Hierarchical query keys:
['blog', 'posts', { status: 'published' }]for surgical invalidation. - Optimistic updates on mutations that hit visible lists.
- Intent-driven stale time: 30s for dashboards, 5min for catalogues.