Guides & concepts
Calling an endpoint
Six call shapes, one declaration.
Every endpoint carries every call shape its method and bindings permit. The ones that would be wrong are typed never.
| Member | Use it for | Available when |
|---|---|---|
| useQuery | Reading in a component | GET, path params bound |
| useSuspenseQuery | Reading under Suspense | GET, path params bound |
| queryOptions | Prefetch, useQueries, typed cache reads | GET, path params bound |
| useMutation | Writing from a component | path params bound |
| mutationOptions | Composing a mutation elsewhere | path params bound |
| useInfiniteQuery | Paginated reads | getNextPageParam declared |
| fetch | Anywhere without React | path params bound |
The chain is immutable
Every withX and onX returns a new endpoint. The original is never mutated, so a shared endpoint stays reusable no matter what a call site binds or instruments.
const traced = api.users.detail
.withHeaders({ 'X-Trace': 'on' })
.onRequest((ctx) => log(ctx));
// api.users.detail is untouched.Passing TanStack options through
The second argument of useQuery is TanStack’s own option type with the error channel pinned to HapiError. Everything you know still works, including select, which may reshape the result.
const { data } = api.users.list.useQuery(undefined, {
staleTime: 30_000,
select: (d) => d.items.length,
});
// ^? number | undefined