---
title: "TanStack Query"
url: https://stacklist.com/card/bdf135d3-ba55-4f00-9797-26d6bcdd1c8d
source_url: "https://tanstack.com/query/latest"
stack: https://stacklist.com/c/technology/stack/203bc96e-6738-4a64-bd6c-5833c6739176
summary: "TanStack Query is a server-state management library that provides caching, fetching, refetching, mutations, and garbage collection for async data across multiple frontend frameworks including React, Vue, Solid, Svelte, Angular, and Lit. It replaces manual data synchronization with declarative APIs, query key-based cache contracts, optimistic updates, and built-in devtools."
tags: "tanstack-query, react-query, server-state, caching, data-fetching, mutations, frontend"
key_entities: "TanStack Query (technology), React (technology), Vue (technology), Solid (technology), Svelte (technology), Angular (technology), TypeScript (technology), server-state management (concept), cache invalidation (concept), optimistic updates (concept), Lit (technology)"
classification: "reference"
content_hash: "sha256:55c9f28913ea55925c189127d7e87b028fb9b243ae011d43f511bdd3c1f7e82d"
acp_version: "0.2"
token_counts_approximate: 2601
visibility: public
agent_accessible: true
status: "final"
---

# TanStack Query

TanStack Query Search AI Ask AI Log In Log In Docs React Latest Search... K Menu Home Blog Frameworks Contributors NPM Stats Community Resources GitHub Discord Menu Menu React Latest Menu Home Blog Frameworks Contributors NPM Stats Community Resources GitHub Discord Server-state manager TanStack Query Stop syncing server data by hand. Query gives async data a cache, a lifecycle, and a set of declarative APIs for fetching, sharing, refetching, mutating, and observing server state across TypeScript applications. 2.3 Billion Total Downloads 66,155,475 Weekly Downloads 49,945 GitHub Stars The server-state standard for modern frontend apps. Read the docs Copy Query Prompt Server-state cache freshness, retries, gc, dedupe Mutation workflow optimistic UI, rollback, invalidate Framework adapters React, Vue, Solid, Svelte, Angular, Lit Built in public Partner-backed Sponsor-supported query client fetching rev 0 / primed Live off Refetch Add issue ['issues', ' router-cache '] Router dashboard p 98 3 observers ['issues', ' project-detail '] Project detail p 91 2 observers ['issues', ' offline-queue '] Offline mutation queue p 84 1 observers useQuery() Components declare the data they need. The cache coordinates fetches, subscribers, freshness, and background updates. status: success isFetching: true staleTime: 3_200 mutation: idle Why Query Server state is not the same problem as client state. Server data is remote, shared, cached, refetched, invalidated, and sometimes stale on purpose. Query handles that lifecycle directly instead of making you recreate it with reducers, effects, and synchronized stores. Important defaults do the boring work. Caching, request dedupe, retries, background refetching, window-focus updates, and garbage collection are already wired for the shape of real apps. Query keys become the cache contract. Keys describe the resource, inputs, filters, and scope so reads, writes, invalidation, prefetching, and devtools all speak the same language. Mutations have a real lifecycle. Handle pending UI, optimistic writes, invalidation, rollback, and follow-up refetches without inventing an ad hoc client-state machine. Devtools make the cache visible. See query keys, observers, freshness, retries, errors, mutations, and cache contents while the app is actually running. 1 Fetch A query function resolves data or throws. Query owns retry, cancellation, and deduping. 2 Share Every observer reads the same cache entry instead of refetching from every component. 3 Revalidate Stale data can stay on screen while a background refetch quietly refreshes it. 4 Collect Unused data sticks around long enough to feel instant, then garbage collection cleans up. queryKey : ['projects', filters] queryFn : fetchProjects staleTime: 30_000 gcTime: 300_000 Cache lifecycle Keep data useful while the network catches up. Query lets stale data remain valuable. Screens can render instantly from cache, refetch in the background, keep previous results during pagination, and recover when the user comes back online. Mutations Writes update the world, then the cache. Query keeps mutation work explicit: optimistic updates, pending states, error recovery, invalidation, and background reconciliation are first-class instead of scattered through components. 1 optimistic write setQueryData(['todos'], next) 2 server mutation await saveTodo(todo) 3 targeted refresh invalidateQueries({ queryKey: ['todos'] }) 4 rollback path onError: restoreSnapshot Result: the UI can feel instant, the server remains the source of truth, and the cache knows exactly what changed. Framework adapters One server-state model, every UI runtime. The core cache model travels across frameworks. Teams can keep the same query keys, invalidation strategy, mutation semantics, and mental model whether the UI is React, Vue, Solid, Svelte, Angular, Preact, or Lit. React Vue Solid Svelte Angular Preact Lit Just a quick look... react preact solid vue svelte angular lit import { useQuery } from &#39;@tanstack/react-query&#39; function Todos () { const { data, isPending, error } = useQuery ({ queryKey: [ &#39;todos&#39; ], queryFn: () =&gt; fetch ( &#39;/api/todos&#39; ). then (r =&gt; r. json ()), }) if (isPending) return &lt; span &gt; Loading ...&lt;/ span &gt; if (error) return &lt; span &gt; Oops !&lt;/ span &gt; return &lt; ul &gt;{data. map (t =&gt; &lt; li key ={t. id }&gt;{t. title }&lt;/ li &gt;)}&lt;/ ul &gt; } export default Todos import { useQuery } from &#39;@tanstack/preact-query&#39; function Todos () { const { data, isPending, error } = useQuery ({ queryKey: [ &#39;todos&#39; ], queryFn: () =&gt; fetch ( &#39;/api/todos&#39; ). then (r =&gt; r. json ()), }) if (isPending) return &lt; span &gt; Loading ...&lt;/ span &gt; if (error) return &lt; span &gt; Oops !&lt;/ span &gt; return &lt; ul &gt;{data. map (t =&gt; &lt; li key ={t. id }&gt;{t. title }&lt;/ li &gt;)}&lt;/ ul &gt; } export default Todos import { createQuery } from &#39;@tanstack/solid-query&#39; function Todos () { const todos = createQuery (() =&gt; ({ queryKey: [ &#39;todos&#39; ], queryFn: () =&gt; fetch ( &#39;/api/todos&#39; ). then (r =&gt; r. json ()), })) return &lt; ul &gt;{todos. data ?. map ((t) =&gt; &lt; li &gt;{t. title }&lt;/ li &gt;)}&lt;/ ul &gt; } export default Todos &lt; script setup lang = &quot;ts&quot; &gt; import { useQuery } from &#39;@tanstack/vue-query&#39; const { data, isPending, error } = useQuery ({ queryKey: [ &#39;todos&#39; ], queryFn: () =&gt; fetch ( &#39;/api/todos&#39; ). then (r =&gt; r. json ()), }) &lt;/ script &gt; &lt; template &gt; &lt; ul v-if = &quot;data&quot; &gt; &lt; li v-for = &quot;t in data&quot; :key = &quot;t.id&quot; &gt;{{ t. title }}&lt;/ li &gt; &lt;/ ul &gt; &lt; span v-else-if = &quot;isPending&quot; &gt; Loading ...&lt;/ span &gt; &lt; span v- else &gt; Oops !&lt;/ span &gt; &lt;/ template &gt; &lt; script lang = &quot;ts&quot; &gt; import { createQuery } from &#39;@tanstack/svelte-query&#39; const todos = createQuery (() =&gt; ({ queryKey: [ &#39;todos&#39; ], queryFn: () =&gt; fetch ( &#39;/api/todos&#39; ). then (r =&gt; r. json ()), })) &lt;/ script &gt; {# if todos. isLoading } Loading ... {: else if todos. isError } Oops ! {: else if todos. isSuccess } &lt; ul &gt; {#each todos. data as t} &lt; li &gt;{t. title }&lt;/ li &gt; {/each} &lt;/ ul &gt; {/ if } import { Component } from &#39;@angular/core&#39; import { injectQuery } from &#39;@tanstack/angular-query-experimental&#39; @Component ({ selector: &#39;todos&#39; , standalone: true , template: ` &lt;ng-container *ngIf=&quot;todos.isPending()&quot;&gt; Loading... &lt;/ng-container&gt; &lt;ul *ngIf=&quot;todos.data() as data&quot;&gt; &lt;li *ngFor=&quot;let t of data&quot;&gt; {{ t.title }} &lt;/li&gt; &lt;/ul&gt; ` , }) export class TodosComponent { todos = injectQuery (() =&gt; ({ queryKey: [ &#39;todos&#39; ], queryFn: () =&gt; fetch ( &#39;/api/todos&#39; ). then (r =&gt; r. json ()), })) } import { LitElement , html } from &#39;lit&#39; import { customElement } from &#39;lit/decorators.js&#39; import { createQueryController } from &#39;@tanstack/lit-query&#39; @customElement ( &#39;todos-list&#39; ) export class TodosList extends LitElement { private todos = createQueryController (this, { queryKey: [ &#39;todos&#39; ], queryFn: () =&gt; fetch ( &#39;/api/todos&#39; ). then (r =&gt; r. json ()), }) render () { const { data, isPending, error } = this. todos () if (isPending) return html `&lt;span&gt;Loading...&lt;/span&gt;` if (error) return html `&lt;span&gt;Oops!&lt;/span&gt;` return html `&lt;ul&gt;${data.map(t =&gt; html` &lt;li&gt;${t. title }&lt;/li&gt; `)}&lt;/ul&gt;` } } Field notes Query is the default answer for async server state. The original copy was right: Query saves code by deleting whole categories of hand-written fetching, loading, retry, cache, and mutation logic. Loved by Developers See what teams are saying " Honestly, if React Query had been around before Redux, I don't think Redux would have been nearly as popular as it was. " Kent C. Dodds @kentcdodds · Epic Web " If I could go back in time and mass myself... I would hand myself a flash drive with a copy of react-query on it. " Kent C. Dodds @kentcdodds · Epic Web " React Query won. There's no denying that. " Theo Browne @t3dotgg · Ping Labs " TanStack Query has been a game-changer for us. We love using it for react-admin. " react-admin @ReactAdmin · Marmelab " The more I use React + Vite + TanStack Router + TypeScript + TanStack Query, the more I love it. " Catalin Pit @catalinmpit · Developer Advocate " Combined with React Query, this stack has been a game-changer for my productivity. " Dominik (TkDodo) @TkDodo · TanStack " Honestly, if React Query had been around before Redux, I don't think Redux would have been nearly as popular as it was. " Kent C. Dodds @kentcdodds · Epic Web " If I could go back in time and mass myself... I would hand myself a flash drive with a copy of react-query on it. " Kent C. Dodds @kentcdodds · Epic Web " React Query won. There's no denying that. " Theo Browne @t3dotgg · Ping Labs " TanStack Query has been a game-changer for us. We love using it for react-admin. " react-admin @ReactAdmin · Marmelab " The more I use React + Vite + TanStack Router + TypeScript + TanStack Query, the more I love it. " Catalin Pit @catalinmpit · Developer Advocate " Combined with React Query, this stack has been a game-changer for my productivity. " Dominik (TkDodo) @TkDodo · TanStack Open source ecosystem Maintainers, education, sponsors, and partners keep Query moving. Query is built in public and taught in public. The maintainers, partner integrations, Query.gg, and GitHub sponsors all stay close to the product story. Maintainers Tanner Linsley Dominik Dorfmeister Vedanta Somnathe Fredrik Höglund Jonghyeon Ko Wonsuk Choi Lachlan Collins Arnoud de Vries Aryan Deora Damian Osipiuk Eliya Cohen View All Maintainers Partners Gold Silver Bronze Query You? We're looking for TanStack Query Partners to join our mission! Partner with us to push the boundaries of TanStack Query and build amazing things together. Let's chat View Previous Partners GitHub Sponsors Become a Sponsor Wow, you've come a long way! Only one thing left to do... Get Started! Blog @Tan_Stack on X.com @TannerLinsley on X.com GitHub YouTube Nozzle.io - Keyword Rank Tracker Ethos Tenets Privacy Policy Terms of Service © 2026 TanStack LLC
