tanstack-fetch
Typed fetch,
made simple.
One request. Data back on success, typed FetchError on failure, AbortSignal honored — shaped for TanStack Query. SSR, SSE, WebSocket, upload, refresh-token, and tRPC stay optional.
- GET
api.get<User[]>('/users', { signal })200[{ id: '1', name: 'Ada' }, …]User[]42ms - GET
api.get<User>('/me')200{ id: 'u_1' } · retried once↻ refreshed User96ms - GET
api.get('/admin')403{ status: 403, code: 'HTTP_ERROR', body }FetchError18ms - POST
api.upload('/files', { file, onUploadProgress }) // tanstack-fetch/sse201{ id: 'f_91', size: '2.4MB' }Upload1.2s - WS
api.ws<Msg, { id: string }>('/rooms/:id', { params, onMessage })101{ text: 'hi' } · reconnected, fresh token↻ refreshed WsSocketlive
What's new
- v2.0.0Latest3.57KB core · Typed live paramsAuth, status and plugins as interceptors on a slim core; sse, ws, transport and stream type params like api.get. Read the post
- v1.8.0WebSocket · WebTransport · NDJSONapi.ws, api.transport and api.stream on tanstack-fetch/live, plus useWs in every framework. Read the post
- v1.7.1Timeouts · URLs · ErrorsTimeoutError on timeouts, ports no longer read as params, binary bodies sent as bytes. Read the post
- v1.7.0doctor · Solid · Angular · Sveltetanstack-fetch doctor health check, real Solid / Angular / Svelte adapters, migrate scaffolds. Read the post
- v1.6.3Migrate CLIRewrite axios, ky, ofetch, $fetch and fetch call sites for TanStack Query. Read the post
- v1.6.1Typed path paramsapi.get<User, { id: number }>(…) params maps and optional body typing on post / put / patch. Read the post
- v1.5.0Vue & NuxtcreateFetchPlugin, useFetch and useSse for Vue 3 and Nuxt, same client as React. Read the post
- v1.4Refresh token · DevToolsToken refresh without hand-written interceptors, a DevTools dock, and useSse without a provider. Read the post
What you get
One client, every call site.
Replace axios, ky, ofetch, or raw fetch with one createFetch client — same queryFn shape on React, Vue, Nuxt, Next.js, Solid, Angular, Svelte, and SvelteKit. Migrate guide + CLI
Return data, throw on failure, and pass the signal. That is the whole queryFn — React, Vue, Solid, Svelte, or Angular Query.
import { createFetch } from 'tanstack-fetch'
import { useQuery } from '@tanstack/react-query'
const api = createFetch({ baseUrl: 'https://api.example.com' })
useQuery({
queryKey: ['users'],
queryFn: ({ signal }) =>
api.get<User[]>('/users', { signal }),
})// data is User[]
[
{ id: '1', name: 'Ada' },
{ id: '2', name: 'Grace' },
]
// isPending → false
// isError → falseWhy not axios?
Same job. Query-shaped answer.
axios, ky, and ofetch are solid HTTP clients. tanstack-fetch is shaped for the call site TanStack Query already expects.
Built for queryFn
axios wraps responses. tanstack-fetch returns data, throws FetchError, and takes signal.
SSR cookies without glue
ssr-forward ships cookie and auth headers from the incoming request. No hand-rolled adapter.
Realtime that can authenticate
SSE over fetch sends Authorization. api.ws, api.transport, and api.stream reuse the same token and refresh-token. No second socket library.
30-second start
Create a client. Pass the signal.
Install the package, create a client, pass signal. That is the whole setup.
import { createFetch } from 'tanstack-fetch'
import { useQuery } from '@tanstack/react-query'
const api = createFetch({ baseUrl: '/api' })
useQuery({
queryKey: ['users'],
queryFn: ({ signal }) => api.get('/users', { signal }),
})What the queryFn gets
- 1Data on successParsed JSON, typed by your generic.
- 2
FetchErroron failurestatus, code, and body — Query's error state. - 3
AbortSignalhonoredUnmounts and refetches cancel in flight.
Features
Everything a queryFn client needs.
Query-shaped client
Success returns data. Failure throws. Cancellation follows AbortSignal.
Typed FetchError
status, code, and body are on the error. isFetchError narrows it.
Status handlers
401, 403, 404, 429, other 4xx, and 5xx each have a hook.
Refresh on 401
createRefreshTokenInterceptor: before (time) and after (first 401), single-flight.
Request DevTools
setupDevtools(api) shows HTTP, SSE, SSR, and tRPC with attempts, timing, and caller file.
3.57KB HTTP core
The HTTP entry is the core. SSE, WebSocket, React, Vue, plugins, and tRPC are separate imports.
Plugins
Named interceptors for retry, trace, and mocks. Eject one on a single call.
SSR forwarding
Next.js and other server renders can forward cookies and auth headers.
SSE with auth
Streams use fetch, so Authorization is a normal header. EventSource cannot send it.
WebSocket with auth
api.ws: Authorization header on Node/Bun/Deno, explicit query/protocol in browsers, reconnect with a fresh token.
WebTransport & NDJSON
api.transport for HTTP/3 datagrams, api.stream for line-by-line JSON that plugs into streamedQuery.
Upload progress
Multipart upload + download progress (onUploadProgress / onDownloadProgress) on tanstack-fetch/sse.
tRPC link
Router and Start can share the same token, plugins, and base client.
OpenAPI codegen
Generate a typed client from an OpenAPI document with the bundled CLI.
React helpers
FetchProvider, useFetch, useSse, and useWs when a component tree should share one client.
Vue & Nuxt helpers
createFetchPlugin, useFetch, useSse, and useWs for Vue 3 and Nuxt apps.
Entry points · v2.0.0
Import only the piece you call.
None of these are required on day one. Add an entry when the feature shows up — Solid, Angular, and Svelte stay on the HTTP core; React / Vue adapters and CLIs are optional.
HTTP core
tanstack-fetchget, post, put, patch, delete, and upload — also Solid, Angular, Svelte, SvelteKit.
Server-sent events
tanstack-fetch/ssefetch-based streams with resume and Authorization.
Live transports
tanstack-fetch/liveSSE + WebSocket + WebTransport + NDJSON streams on one client.
Plugins
tanstack-fetch/pluginsRetry, trace, SSR forward, and status helpers.
React
tanstack-fetch/reactProvider, useFetch, useSse, and useWs for a shared client.
Vue & Nuxt
tanstack-fetch/vuePlugin, useFetch, useSse, and useWs for Vue 3 and Nuxt.
Solid
tanstack-fetch/solidProvider, useFetch, useSse, and useWs for Solid.
Angular
tanstack-fetch/angularprovideFetchClient, injectFetch, useSse, and useWs signals.
Svelte
tanstack-fetch/sveltesetFetchClient, getFetchClient, useSse, and useWs stores.
tRPC
tanstack-fetch/trpcA tRPC link that reuses createFetch.
DevTools
tanstack-fetch/devtoolsA request dock for HTTP, SSE, SSR, and tRPC.
Migrate CLI
tanstack-fetch migrateRewrite axios / ky / ofetch / fetch — scaffold React, Vue, Nuxt, Next, Solid, Angular, Svelte.
Doctor CLI
tanstack-fetch doctorHealth-check deps, createFetch usage, legacy clients, and missing signal.
OpenAPI CLI
tanstack-fetch generateTurn an OpenAPI document into a typed client.
Playground
Click a status. Open a socket. It runs in the browser.
createFetch against mock servers: HTTP status handlers, WebSocket, WebTransport, and NDJSON streams. It is the same client, not a screenshot.
Live demo · real createFetch
Trigger HTTP statuses
Mock fetch returns the code you click. Handlers fire before FetchError is thrown — including 429 with Retry-After.
Tap a status — real createFetch + mock fetch
Event log
Handlers and throws show up here.
const api = createFetch({
interceptors: [
createStatusInterceptor({
401: () => logout(),
429: ({ context }) => {
const waitMs = parseRetryAfter(context.response?.headers)
// show toast / backoff…
},
'4xx': ({ status }) => console.warn('4xx', status),
}),
],
})Open in StackBlitz · v2.0.0
Run the examples in the browser.
StackBlitz for React demos (Query, Next.js, SSE, tRPC, upload). Docs cover the same api.sse / api.ws / api.stream / createTRPCFetchClient patterns on Vue, Nuxt, Solid, Angular, Svelte, and SvelteKit.
- TanStack Query · React StackBlitz Docs
- Next.js SSR StackBlitz Docs
- Nuxt SSR Docs
- Upload StackBlitz Docs
- SSE · React StackBlitz Docs
- SSE · Start / Remix / SolidStart / Vue / Solid Docs
- WebSocket · WebTransport · NDJSON Docs
- tRPC · TanStack Start + Query + Router context Docs
- tRPC · React StackBlitz Docs
- tRPC · SolidStart / Remix / Vue / Solid Docs
- Auth status StackBlitz Docs
- Live playground Docs
- Migrate · Solid / Angular / Svelte Docs
Comparison
Compared with the usual clients.
axios, ky, and ofetch are all capable HTTP clients. tanstack-fetch is shaped for the TanStack Query call site, and for the SSR, SSE, and tRPC cases that sit next to it.
| Feature | axios | ky | ofetch | |
|---|---|---|---|---|
| queryFn returns data, throws, and takes signal | First-class | Partial | Partial | Partial |
| Typed error with status and body | First-class | Partial | Partial | Partial |
| Handlers for 401 through 429 | First-class | Not built in | Not built in | Not built in |
| Refresh before expiry + after first 401 | First-class | Partial | Not built in | Not built in |
| Next.js cookie forwarding | First-class | Not built in | Not built in | Not built in |
| SSE that can send Authorization | First-class | Not built in | Not built in | Not built in |
| WebSocket with auth, reconnect, and send queue | First-class | Not built in | Not built in | Not built in |
| NDJSON streaming (POST body + headers) | First-class | Partial | Partial | Partial |
| Upload progress | First-class | First-class | Not built in | Not built in |
| Request DevTools for HTTP, SSE, SSR, tRPC | First-class | Not built in | Not built in | Not built in |
| tRPC link on the same client | First-class | Not built in | Not built in | Not built in |
| Built in | 11/11 | 1/11 | 0/11 | 0/11 |
- First-class
- Possible, with extra adaptation
- Not built in
Start with one request.
Add a token when you need auth, a plugin when you need retry, another entry when you need SSE, WebSocket, WebTransport, or NDJSON streams. The queryFn does not change. The first call is a few lines.
