DEV Community

mohammad garmabi
mohammad garmabi

Posted on

tanstack-fetch vs ky vs Axios: Which HTTP Client Fits TanStack Query?

If you're using React + TanStack Query, you've probably written code like this:

queryFn: async ({ signal }) => {
  const { data } = await axios.get('/users', { signal })
  return data
}
Enter fullscreen mode Exit fullscreen mode

Or with ky:

queryFn: ({ signal }) =>
  ky.get('/users', { signal }).json<User[]>()
Enter fullscreen mode Exit fullscreen mode

Both are perfectly valid.

But I kept asking myself:

Why does the HTTP client need to make my TanStack Query queryFn adapt its response?

That question led me to build tanstack-fetch.


The idea

TanStack Query is responsible for server state.

The HTTP client should be responsible for HTTP transport.

So the architecture becomes:

React
  ↓
TanStack Query
  ↓
tanstack-fetch
  ↓
Fetch
Enter fullscreen mode Exit fullscreen mode

The HTTP client should fit naturally into the queryFn contract.

That means:

  • Return the actual data
  • Throw on HTTP errors
  • Support AbortSignal
  • Keep TypeScript types
  • Avoid unnecessary response transformations

Compare the APIs

Axios

queryFn: async ({ signal }) => {
  const { data } = await axios.get<User[]>('/users', {
    signal,
  })

  return data
}
Enter fullscreen mode Exit fullscreen mode

ky

queryFn: ({ signal }) =>
  ky.get('/users', { signal }).json<User[]>()
Enter fullscreen mode Exit fullscreen mode

tanstack-fetch

queryFn: ({ signal }) =>
 api.get<User[]>('/users', { signal })
Enter fullscreen mode Exit fullscreen mode

The difference is small.

But across hundreds of query functions, small pieces of glue code add up.


Authentication is another problem

Real applications usually need more than:

fetch(url)
Enter fullscreen mode Exit fullscreen mode

You may need:

  • Access tokens
  • Refresh tokens
  • Concurrent 401 handling
  • Request retries
  • Interceptors
  • SSR cookies
  • SSE
  • Request cancellation

For example, if five requests receive 401 simultaneously, you generally don't want five refresh requests.

You want:

401 ─┐
401 ─┤
401 ─┼──→ one refresh → retry requests
401 ─┤
401 ─┘
Enter fullscreen mode Exit fullscreen mode

tanstack-fetch includes a refresh-token interceptor with single-flight behavior.


tanstack-fetch vs ky vs Axios

tanstack-fetch ky Axios
TanStack Query focused ✅ ❌ ❌
Fetch-based ✅ ✅ ❌
Typed errors ✅ ✅ ✅
AbortSignal ✅ ✅ ✅
Token refresh Built-in Custom Custom
Single-flight refresh ✅ Custom Custom
SSR support First-class Manual Manual
SSE ✅ Custom Custom
Ecosystem New Mature Very mature

This isn't about declaring a universal winner.

It's about choosing the right abstraction for your architecture.


When should you use tanstack-fetch?

It makes the most sense when:

  • You're already using TanStack Query
  • You want simpler queryFns
  • You want a typed Fetch-based client
  • You need auth refresh
  • You need SSR support
  • You need authenticated SSE
  • You're starting a new application
  • You're considering migrating from Axios, ky, ofetch, or Fetch

If you simply want a small Fetch wrapper, ky may be a better fit.

If you're already deeply invested in Axios, there may be no reason to migrate.


Migration

Migration is often harder than choosing a new library.

That's why tanstack-fetch includes a migration CLI that can scan existing HTTP call sites and help migrate Axios, ky, ofetch, and Fetch code toward a TanStack Query-oriented architecture.

The goal isn't:

Rewrite everything.

It's:

Make migration incremental and practical.


The bigger idea

I don't think every React application needs a new HTTP client.

But if TanStack Query is already the center of your data layer, your HTTP client should ideally complement it instead of forcing every query function to adapt between two different abstractions.

That's the idea behind tanstack-fetch.

TanStack Query → Server State

tanstack-fetch → HTTP Transport

Fetch → Network Primitive


tanstack-fetch is an open-source project and is not an official TanStack project.

If you're interested, check out the project and let me know what you think.

Top comments (0)