HTTP requests

fetch()

Baseline widely available
  • Chrome42
  • Edge14
  • Firefox39
  • Safari10.1

Features it needs

  • FetchWidely available

axios was written when fetch was not everywhere and XMLHttpRequest was the floor. Most of what it adds is now a few lines at the call site: fetch resolves for any response the server sent, so you check response.ok yourself, and it hands back a stream, so you call response.json(). Cancellation is an AbortController, and a timeout is AbortSignal.timeout() passed as the signal. Interceptors and upload progress are what is genuinely missing, and they are the reasons to keep the library.

When this applies

Making HTTP requests from the browser or from Node 18.0.0 and up.

The native approach

const res = await fetch("/api/items", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(payload),
  // Aborts and rejects after five seconds.
  signal: AbortSignal.timeout(5000),
});

// fetch only rejects on a network error, so check the status yourself.
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
const items = await res.json();

MDN reference

When the dependency is still right

An answer that always says "the platform covers it" is worse than no answer. These are the cases where this one does not hold.

  • You use interceptors to attach auth headers or refresh a token on 401 across every call. fetch has no hook for that, so it becomes a wrapper every request has to route through.
  • You rely on a 4xx or 5xx rejecting. fetch resolves for any response the server sent, so every call site needs an explicit response.ok check and existing catch blocks quietly stop firing.
  • You need upload progress. Download progress can come off the response stream, but tracking bytes sent still needs XMLHttpRequest, which is what axios uses underneath.
  • You share one client with Node below 18.0.0, where there is no global fetch, or you depend on axios features with no equivalent: XSRF cookie handling, automatic transforms, or the adapter system.
  • Your tests mock axios directly. Moving to fetch means rewriting those mocks, which is real work for no behaviour change.
  • You need a request timeout below Chrome 124, Safari 16 or Firefox 100. fetch itself is far older than all three, but AbortSignal.timeout() is not, so an older target needs a setTimeout calling controller.abort().

Packages this covers