Skip to content

Getting started ​

tanstack-fetch logo

Install ​

tanstack-fetch on npmtanstack-fetch weekly downloadstanstack-fetch monthly downloadstanstack-fetch total downloads

Peers are optional. Pick the stack you use:

bash
# Vue / Nuxt
npm install tanstack-fetch vue
# optional Query
npm install @tanstack/vue-query

For SSE, WebSocket / WebTransport / NDJSON (tanstack-fetch/live), React, Vue/Nuxt, or tRPC, import the matching entry — same package.


React quickstart ​

Framework

React · @tanstack/react-query

ts
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 }),
})

That’s it: returns data, throws FetchError on HTTP errors, honors Query’s signal.


Vue quickstart ​

Framework

Vue 3 · optional @tanstack/vue-query · Nuxt-ready

ts
import { createFetch } from 'tanstack-fetch'
import { useQuery } from '@tanstack/vue-query'

const api = createFetch({ baseUrl: 'https://api.example.com' })

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

Or inject a shared client with tanstack-fetch/vue.

Framework-agnostic — works in React, Vue, Nuxt, and Next.js.

ts
// src/lib/api.ts
import { createFetch } from 'tanstack-fetch'
import {
  createAuthInterceptor,
  createRetryIdempotentInterceptor,
  createStatusInterceptor,
  createTraceInterceptor,
} from 'tanstack-fetch/plugins'

export const api = createFetch({
  baseUrl: import.meta.env.VITE_API_URL ?? 'https://api.example.com',
  interceptors: [
    createAuthInterceptor({ getToken: () => localStorage.getItem('access_token') }),
    createStatusInterceptor({
      401: () => {
        localStorage.removeItem('access_token')
        window.location.href = '/login'
      },
    }),
    createTraceInterceptor(),
    createRetryIdempotentInterceptor(),
  ],
})

The core tanstack-fetch entry is slim (3.57KB) — auth, status handlers and plugins are interceptors. Prefer getToken / onUnauthorized / plugins: [...] shortcuts or need upload()? Import createFetch from tanstack-fetch/sse (or /live) — same options, plus those. See Core entry points.

Quick taste — typed params & body ​

ts
import { createFetch, isFetchError } from 'tanstack-fetch'
import type { NoParams } from 'tanstack-fetch'
import { createAuthInterceptor } from 'tanstack-fetch/plugins'

const api = createFetch({
  baseUrl: import.meta.env.VITE_API_URL,
  interceptors: [createAuthInterceptor({ getToken: () => localStorage.getItem('access_token') })],
})

const user = await api.get<User, { id: string | number }>('/users/:id', { params: { id: '1' } })
await api.post<User, NoParams, { name: string }>('/users', { body: { name: 'Ada' } })

try {
  await api.get('/missing')
} catch (error) {
  if (isFetchError(error)) console.log(error.status, error.message)
}

Types — one sentence

  • No generics → params inferred from the URL (:id / {id})
  • get<T, Params> → response type + params map (path must contain those keys)
  • post<T, Params, Body> → optional third generic for the request body (NoParams skips params)

Next steps ​

GoalPage
Typed URL params / body(see Quick taste above)
Cursor / agent skillAgent skill
Token + 401 / 403 / 404Configuration
Refresh tokenRefresh token
React / Vue QueryTanStack Query
React helpersReact
Vue / Nuxt helpersVue & Nuxt
Next.js / Nuxt cookiesSSR
StreamsSSE
WebSocket / NDJSONWebSocket, WebTransport & streams
SSE authEventSource auth headers
tRPCtRPC

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