Practical React Query
use-q is an opinionated way to use TanStack Query — TkDodo's Practical React Query series, encoded as a schema-driven client.
use-q is not a new data-fetching library. It is an opinionated way to use TanStack Query.
The opinions come from Dominik Dorfmeister (TkDodo)'s Practical React Query series: treat the cache as a server-state manager, never hand-write query keys, colocate a query abstraction, invalidate by describing relationships, transform with select, and keep TypeScript inference flowing from the query function.
You still mount a QueryClientProvider. You still pass staleTime, select, and enabled. use-q makes those recommended patterns the path of least resistance so every app doesn't reinvent a query-key factory and a mutation-invalidation graph.
This page is a map, not a restatement of the series. When you want the why behind a default, follow the link to TkDodo. When you want the how in this library, follow the use-q guide next to it.
What use-q bakes in
A query abstraction, not a new mental model
Creating Query Abstractions and The Query Options API argue for a single place that owns queryKey + queryFn (and the types). createApiClient is that place: one schema produces useQ, useM, queryKeys, and the fetcher. React Query API Design — Lessons Learned is the longer argument for co-locating those.
Hierarchical query keys you never type twice
Effective React Query Keys: array keys, coarse-to-fine, plus a factory. use-q keys are always ["api", method, resolvedPath, searchParams]. The client's queryKeys factory is the factory. The query function always receives TanStack's queryFn context (including signal) — you don't thread it yourself. See Query keys.
Automatic invalidation after mutations
Automatic Query Invalidation after Mutations is the problem tags / invalidatesTags solve. You describe which reads depend on which writes in the schema; useM invalidates matching queries in onSettled, as Mastering Mutations recommends — success and error, so rollbacks still refetch the truth. See Tag invalidation.
Transforms and render isolation via select
Don't map in the queryFn. Pass select to useQ — data transformations, render optimizations, and selectors, supercharged.
Types inferred from the schema, not from generics
React Query and TypeScript and Type-safe React Query: let the query function (here: the RouteDefinition) produce the types. You almost never pass generics to useQ / useM.
Errors and status as Query intended them
React Query Error Handling — handle errors where you have the context: globally (onError on the fetcher), per mutation, or with an error boundary (ApiErrorBoundary + useSuspenseQ). Status Checks in React Query still apply: prefer isPending / isError / isSuccess over treating isLoading as the only gate.
Optimistic updates that cancel in-flight queries
useM's optimisticUpdates follow Concurrent Optimistic Updates: cancelQueries, snapshot, setQueryData, rollback on error, invalidate on settle. See Optimistic updates.
Seed the cache; don't copy server state into React state
The cache is the store for server data — React Query as a State Manager, Thinking in React Query, Why You Want React Query. Prefetch and hydrate with useQClient and SSR & loaders (seeding the query cache, placeholder vs initial data, React Query meets React Router). Put a QueryClient in context, not query results — React Query and React Context.
What we don't bake in
The series covers more than a client library should own. use-q leaves these to your app — and to TkDodo:
- WebSockets — Using WebSockets with React Query. Query is a cache; push updates into it with
useQClient().setData/queryClient.setQueriesData. - Offline persistence — Offline React Query. Pass your own
QueryClient(see Bring your own QueryClient). - Forms — React Query and Forms.
useMsubmits; form state stays in the form library. - Testing — Testing React Query. One
QueryClientper test,queries.retry: false. - Whether you need Query at all — You Might Not Need React Query. use-q is for server state that benefits from a cache.
Two more posts are useful background without being APIs we wrap: Inside React Query (how the observer model works) and React Query — The Bad Parts (query keys and invalidation boilerplate are two of the sharp edges this library exists to blunt). TanStack Router and Query is the Router-specific integration; our SSR & loaders guide shows the shared-cache pattern without duplicating that post.
Feature → post
The series index — and every later part — lives on Practical React Query (#1). There is also a React Query FAQs post for the questions that come up after the defaults click.