TanStack Query (formerly React Query) is a powerful, framework-agnostic data-fetching and caching library for building fast, reactive, and resilient web applications. It manages server state, caching, background sync, pagination, and much more—so you can focus on building features, not fetching data.
- Smart Caching – Automatic and configurable caching of server data, minimizing unnecessary requests.
- Background Synchronization – Keep data fresh by refetching in the background, on focus, or reconnect.
- Mutation Management – Powerful tools for handling create, update, and delete operations with optimistic updates and rollback.
- Pagination & Infinite Queries – Effortlessly manage paginated or infinite scrolling data.
- Devtools – Inspect and debug your queries and mutations in real time.
- Framework Agnostic – Works with React, Solid, Svelte, Vue, and more.
- First-Class Typescript Support – Full type safety for queries and mutations.
-
Install the Package
- For React:
npm install @tanstack/react-query
- For React:
-
Set Up the Query Client
- Wrap your app with the
QueryClientProviderand create aQueryClientinstance.import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; const queryClient = new QueryClient(); function App() { return ( <QueryClientProvider client={queryClient}> {/* Your app */} </QueryClientProvider> ); }
- Wrap your app with the
-
Basic Data Fetching Example
- Use the
useQueryhook to fetch and cache data.import { useQuery } from '@tanstack/react-query'; function Todos() { const { data, isLoading, error } = useQuery({ queryKey: ['todos'], queryFn: () => fetch('/api/todos').then(res => res.json()) }); if (isLoading) return <span>Loading...</span>; if (error) return <span>Error: {error.message}</span>; return ( <ul> {data.map(todo => <li key={todo.id}>{todo.title}</li>)} </ul> ); }
- Use the
-
Mutations Example
- Use the
useMutationhook for creating/updating/deleting data.import { useMutation, useQueryClient } from '@tanstack/react-query'; function AddTodo() { const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: newTodo => fetch('/api/todos', { method: 'POST', body: JSON.stringify(newTodo), headers: { 'Content-Type': 'application/json' } }), onSuccess: () => { queryClient.invalidateQueries(['todos']); } }); // ...form logic to call mutation.mutate(newTodo) }
- Use the
-
Devtools
- Install and use the devtools for debugging:
npm install @tanstack/react-query-devtools
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; <QueryClientProvider client={queryClient}> {/* Your app */} <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider>
- Install and use the devtools for debugging:
- Fetching and caching remote data in any modern frontend framework.
- Synchronizing server and client state (e.g., after mutations).
- Background data refresh for real-time or near-real-time UIs.
- Managing paginated or infinite-scroll data.
- Optimistically updating UI for a responsive user experience.
- Complex apps with lots of remote data dependencies.
import { useQuery } from '@tanstack/react-query';
function Example() {
const { data, isLoading } = useQuery({
queryKey: ['example'],
queryFn: () => fetch('/api/example').then(res => res.json()),
});
if (isLoading) return 'Loading...';
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}Learn more at tanstack.com/query