Skip to content

Why this API?

Mental model: createFetch → queryFn → data or FetchError

TanStack Query’s contract for a queryFn is simple. Most HTTP clients fight it.

TanStack Query needstanstack-fetch does
queryFn returns dataapi.get<T>()Promise<T>
Failures must throwHTTP errors throw FetchError
CancellationPass { signal } from queryFn
Typed errorsisFetchError(error)status, code, body

Designed around Query

ts
useQuery({
  queryKey: ['users'],
  queryFn: ({ signal }) => api.get<User[]>('/users', { signal }),
})

No wrapping if (!res.ok), no Result-object dance unless you opt in with throwOnError: false.

Tiny by default

Import only what you need. The HTTP core stays around ~3.5KB gzip. SSE, React, plugins, and tRPC are separate entries.

First-class status handling

ts
createFetch({
  getToken: () => localStorage.getItem('access_token'),
  onUnauthorized: () => logout(), // 401
  onForbidden: () => toast.error('Forbidden'), // 403
  onNotFound: () => toast.error('Missing'), // 404
  onServerError: ({ status }) => console.error(status), // 5xx
})

Handlers run before the error is thrown — Query still sees isError / FetchError.

MIT Licensed · Created by Mohammad Garmabi · Not an official TanStack package