TanStack Query manages server state on the client: caching, background refetching, retries and mutations. It is a good fit for interactive dashboards and client-heavy apps; it is unnecessary for a page that can fetch on the server.
Key takeaways
- Query keys are the cache identity; make them stable and specific.
staleTimecontrols how long data is considered fresh;gcTimecontrols how long inactive data stays in memory.- Mutations can invalidate queries or update the cache optimistically.
- Prefer the simplest boundary that keeps data and authorisation on the server.
What matters in practice
- Use the Next.js integration to hydrate the cache from server-rendered data.
- Do not use it as a global state manager for UI state.
How to implement it
- Create the provider. Put a
QueryClientProvideraround the client tree. - Define query keys. One factory per feature so invalidation is predictable.
- Fetch on the server where possible. Hydrate the client cache with initial data.
- Set freshness. Use a realistic
staleTimefor the data, not a global default. - Handle mutations. Invalidate affected queries and show optimistic feedback where safe.
- Observe. Log query errors and slow requests; add retries only for transient failures.
A working example
const queryKeys = {
products: (filters: Filters) => ["products", filters] as const,
};
export function useProducts(filters: Filters) {
return useQuery({
queryKey: queryKeys.products(filters),
queryFn: () => fetchProducts(filters),
staleTime: 30_000,
});
}
Production checklist
| Area | Check |
|---|---|
| Provider | One client per request in SSR; one per app in the browser |
| Keys | Stable, serialisable and scoped by feature |
| Freshness | staleTime and gcTime set per data type |
| Mutations | Invalidation or optimistic update with rollback |
| Hydration | Server data dehydrated into the client cache |
| Errors | Retry policy and user-visible error states |
Common mistakes
- Using array index or object identity in a query key.
- Setting
staleTime: Infinityfor data that changes. - Duplicating server state into a global store.
- Forgetting to invalidate after a mutation.
When this is the wrong tool
Every tool has a boundary. If the team is small, the use case is simple and the operational cost is high, a simpler stack may be better. The right choice is the one you can debug, secure and hand over without the original author.
Rollout plan
- Prove one slice. Use TanStack Query v5 for one real route or feature, not the whole product.
- Set the boundary. Write down what stays on the server, what runs on the client and how data crosses the boundary.
- Add the safety net. Types, validation, tests and error handling around the new slice.
- Measure. Check bundle size, latency, error rate and the developer experience before expanding.
- Document and hand over. Record the pattern, the pitfalls and the version constraints.
Testing strategy
| Layer | What to test | Why |
|---|---|---|
| Types | Strict compile and no unjustified any | Catches contract drift early |
| Unit | Pure logic, validation and state transitions | Fast feedback |
| Integration | API, database and auth boundaries | Most production failures live here |
| End-to-end | The critical user journey | Proves the wiring |
| Operations | Logs, errors, retries and rollback | A release is not finished at deploy |
Operational checklist
- Pin the runtime and dependency versions; test upgrades in a branch.
- Keep secrets on the server and validate every external payload.
- Add structured logs with a request ID, but never log tokens or personal data.
- Set a performance or bundle budget and check it in CI.
- Write a short runbook for the most likely failure.
Frequently asked questions
Not for every page. Use it when the client needs caching, background refresh and mutations across views. Server components can fetch initial data without it.
staleTime is how long data is fresh; gcTime is how long inactive data remains in memory. A long gcTime with a short staleTime gives fast back-navigation with a background refresh.
Prefetch on the server, use parallel queries and hydrate the cache. On the client, use useQueries or prefetch the next route's data.
It can manage submission state, but form state is usually local. Use a form library for field state and TanStack Query for the server mutation.
Sources and further reading
- TanStack Query documentation (tanstack.com)
- Next.js data fetching (nextjs.org)
- React documentation (react.dev)
Related reading
Need an implementation review?
Send the repository or the design. I will review the boundary, the failure modes and the parts that will be expensive to change later.
How to cite this guide: Nur Hossain Repon, “TanStack Query v5 data fetching guide 2026”, Nhrepon Portfolio, reviewed October 2026, https://nhrepon.com/posts/tanstack-query-v5-data-fetching-guide-2026.





Comments
No comments yet.