cheat sheet

axios

Package-level reference for axios — interceptors, request configuration, error handling, and the migration story from 0.x to 1.x.

axios

What it is

axios is a promise-based HTTP client that works in Node and in browsers from a single API surface. It predates fetch being universally available and continues to ship because of its ergonomic defaults: automatic JSON parsing, interceptors, request cancellation, automatic transforms, and a typed config object.

Reach for axios when you want one HTTP library that behaves the same in Node and in browsers with batteries included (retries via axios-retry, mocking via axios-mock-adapter, response schemas via zod). Reach for native fetch when the modern Web APIs (AbortController, streaming response bodies, ReadableStream) and zero-dependency footprint matter more than convenience.

Install

bash
npm install axios

Output: added axios to dependencies

bash
pnpm add axios

Output: added 1 package, linked from store

bash
yarn add axios

Output: added axios

bash
bun add axios

Output: installed axios

axios ships its own TypeScript types — no @types/axios needed.

Versioning & Node support

Current line is axios@1.x (released 2022 after the long 0.27 era). The 1.x series broke a handful of edge-case behaviours but stabilised the API.

  • Node 14+ is the supported floor; Node 18+ is recommended (native fetch becomes a backup transport).
  • Browser support tracks evergreen browsers; IE11 was dropped in 1.x.
  • Dual ESM/CJS published — bundlers pick automatically. ESM entry under dist/esm/.
  • TypeScript declarations bundled in the package — no separate @types install.
  • Semver is observed; the 0.x → 1.x leap was the only major break in the modern era.

Package metadata

  • Maintainer: Axios contributors (lead: Jasonyk Saunders / Matt Zabriskie historically)
  • Project home: github.com/axios/axios
  • Docs: axios-http.com
  • npm: npmjs.com/package/axios
  • License: MIT
  • First released: 2014
  • Downloads: consistently in the top 10 packages on npm (tens of millions of weekly downloads)

Peer dependencies & extras

Axios has no peer deps — install and use. Common companions:

  • axios-retry — retry-on-failure with exponential backoff
  • axios-mock-adapter — intercept and stub requests in tests
  • axios-cache-interceptor — caching layer on top of axios
  • form-data — multipart bodies for Node (browsers use the built-in FormData)
  • qs — alternative query-string serialiser (axios uses a basic built-in by default)
  • zod / valibot — schema-validate response payloads

Alternatives

PackageTrade-off
native fetchBuilt into Node 18+ and all browsers. No deps. More boilerplate (no auto-JSON, no interceptors).
kyTiny fetch wrapper. ESM-only. Modern API; smaller bundle than axios.
gotPowerful Node-only client. Streams, retries, hooks. Not for browsers.
undiciNode's HTTP/1.1 + HTTP/2 client under the hood of fetch. Lower-level.
node-fetchPolyfill of fetch for old Node. Largely obsolete now that Node ships fetch.
@tanstack/queryNot an HTTP client — a cache around any client. Pair with axios or fetch.

Real-world recipes

GET with timeout and JSON

typescript
import axios from "axios";

const { data } = await axios.get<{ id: number; title: string }>(
  "https://api.example.com/posts/1",
  { timeout: 5000 },
);
console.log(data.title);

Output: logs the post title; throws AxiosError with code: 'ECONNABORTED' if the request exceeds 5 seconds.

POST JSON with auth header

typescript
const res = await axios.post(
  "https://api.example.com/login",
  { email: "alice@example.com", password: "secret" },
  { headers: { "X-API-Key": process.env.API_KEY! } },
);
const token = res.data.token as string;

Output: posts the JSON body, response is auto-parsed; Content-Type: application/json set automatically.

Pre-configured instance per service

Wrap a base URL + headers in an axios.create instance so callers do not repeat them.

typescript
import axios from "axios";

export const api = axios.create({
  baseURL: "https://api.example.com",
  timeout: 10_000,
  headers: { "X-Client": "myapp/1.0" },
});

const me = await api.get("/me");

Output: subsequent calls inherit the base URL, timeout, and client header.

Interceptor: refresh token on 401

typescript
api.interceptors.response.use(
  (res) => res,
  async (error) => {
    if (error.response?.status === 401 && !error.config._retry) {
      error.config._retry = true;
      const { data } = await api.post("/auth/refresh");
      error.config.headers.Authorization = `Bearer ${data.token}`;
      return api(error.config);
    }
    return Promise.reject(error);
  },
);

Output: intercepts a 401, refreshes the token, and replays the original request once.

Upload with progress

typescript
import fs from "node:fs";
import FormData from "form-data";

const form = new FormData();
form.append("file", fs.createReadStream("./large.zip"));

await axios.post("https://api.example.com/upload", form, {
  headers: form.getHeaders(),
  onUploadProgress: (e) => {
    if (e.total) console.log(`${Math.round((e.loaded / e.total) * 100)}%`);
  },
});

Output: streams the file and prints upload percentage; works identically in browsers using the built-in FormData.

Cancel an in-flight request

typescript
const controller = new AbortController();
const promise = axios.get("https://api.example.com/slow", { signal: controller.signal });

setTimeout(() => controller.abort(), 1000);

try {
  await promise;
} catch (err) {
  if (axios.isCancel(err)) console.log("Cancelled");
}

Output: aborts after 1 second; axios.isCancel distinguishes cancellation from other errors.

Retry with axios-retry

typescript
import axios from "axios";
import axiosRetry from "axios-retry";

axiosRetry(axios, {
  retries: 3,
  retryDelay: axiosRetry.exponentialDelay,
  retryCondition: (err) => axiosRetry.isNetworkOrIdempotentRequestError(err),
});

Output: transient 5xx and network errors retry up to 3 times with exponential backoff (no per-call config needed).

Production deployment

Axios is a library — deployment depends on the host (Node server, browser bundle, Lambda, edge worker). The axios-specific concerns are timeouts, connection pooling, and retry policy.

  • Always set timeout. The default is no timeout — a hung server hangs your process. 5–30 seconds is typical.
  • Keep-alive in Node. Set a custom httpAgent / httpsAgent with keepAlive: true so connections are reused across requests in a long-lived process.
  • Edge runtimes (Cloudflare Workers, Vercel Edge). Axios's adapter expects Node's http module by default. On the edge, force the fetch adapter: axios.create({ adapter: "fetch" }).
  • TLS verification. Production code should NEVER set rejectUnauthorized: false. Use proper certificate stores; if you must override for dev, gate on NODE_ENV !== 'production'.
  • Proxy support. httpsAgent: new HttpsProxyAgent(process.env.HTTPS_PROXY) for corporate proxies. Axios's proxy config is also supported but limited.

A typical Node service uses a single axios.create instance per upstream service with a keep-alive agent and a retry interceptor.

Performance tuning

  • Reuse the same instance. Each axios.create call sets up new transformers; reusing the instance amortises that.
  • Disable JSON transform if you do not need it. responseType: 'arraybuffer' or 'stream' skips automatic parse.
  • Use streaming for large bodies. responseType: 'stream' returns a Node readable; pipe directly to disk or to another HTTP call.
  • Avoid JSON.stringify overhead twice. Pass an object as data and axios stringifies once; passing a pre-stringified string adds nothing but bytes.
  • Connection pooling. A keep-alive httpsAgent cuts TLS handshake cost dramatically. Without it each request does a full handshake.
  • Bundle size in browsers. axios is ~30 KB minified, ~12 KB gzipped. For browser bundles where every KB matters, prefer ky (~6 KB) or native fetch.

Version migration guide

0.x → 1.x (the only major break)

Most code keeps working — the changes are around edge cases.

Area0.x1.x
Default exportCJS defaultNamed ESM + dual CJS
transformRequest / transformResponseCould be a single functionMust be an array
paramsSerializerFunctionObject with encode / serialize keys (function form still supported)
Form dataManual handlingFormData auto-detected and serialised
CancellationCancelToken onlyAbortSignal (Web standard) + CancelToken kept for back-compat
TypeScriptLess strict genericsGenerics on response data tightened

Before (0.x):

typescript
import axios from "axios";
const source = axios.CancelToken.source();
axios.get("/x", { cancelToken: source.token });
source.cancel("user navigated away");

After (1.x):

typescript
import axios from "axios";
const controller = new AbortController();
axios.get("/x", { signal: controller.signal });
controller.abort();

Output: same cancellation semantics with the Web-standard API.

Migration checklist:

  1. Bump to axios@1.x. Most code compiles unchanged.
  2. Replace CancelToken with AbortController (kept working but is now legacy).
  3. If using a custom paramsSerializer, verify the object form.
  4. Check that transformRequest / transformResponse are arrays (a single function silently does the wrong thing in 1.x).
  5. Update any prototype-pollution-sensitive code that relied on 0.x's looser merge — see Security.

Security considerations

  • CVE-2023-45857 (prototype pollution). Axios 0.x had a formToJSON helper that allowed prototype pollution via crafted form data. Fixed in 1.6.0. Upgrade.
  • CVE-2024-39338 (SSRF). Path traversal in URL paths could be used for SSRF when a baseURL was set. Fixed in 1.7.4. Upgrade.
  • Server-side request forgery. When the URL is user-supplied, validate the host against an allowlist before calling axios. Axios will happily call http://169.254.169.254/ (cloud metadata).
  • Header injection. Untrusted values in request headers (e.g. Authorization: Bearer ${user_token}) need newline stripping; modern Node rejects \r\n in header values, but be defensive.
  • TLS verification. Never disable in production. rejectUnauthorized: false defeats HTTPS entirely.
  • Interceptors execute in user code. A logging interceptor that prints config.headers to a log file leaks bearer tokens. Redact known secret headers (Authorization, Cookie, X-API-Key).
  • Response size limits. Axios buffers the whole response by default. A hostile server can OOM your process. Set maxContentLength and maxBodyLength.

Testing & CI integration

Mock with axios-mock-adapter

typescript
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { describe, it, expect, beforeEach } from "vitest";

const mock = new MockAdapter(axios);

beforeEach(() => mock.reset());

describe("GET /users", () => {
  it("returns users", async () => {
    mock.onGet("/users").reply(200, [{ id: 1, name: "Alice" }]);
    const { data } = await axios.get("/users");
    expect(data).toHaveLength(1);
  });
});

Output: test passes without hitting the network; subsequent calls without a matching stub fail loudly.

Real HTTP with nock

typescript
import nock from "nock";

nock("https://api.example.com")
  .get("/posts/1")
  .reply(200, { id: 1, title: "hello" });

Output: intercepts requests at the Node http layer, so axios sees a real-looking response with no socket.

Ecosystem integrations

PackageRole
axios-retryRetry transient failures with backoff
axios-mock-adapterTest stub layer
axios-cache-interceptorIn-memory / persistent response cache
axios-rate-limitToken-bucket rate limiting
@nestjs/axiosNest.js wrapper for DI containers
zodValidate response shapes at runtime
pino-axiosLogging plugin

Troubleshooting common errors

AxiosError: timeout of N ms exceeded — request exceeded the timeout. Increase, or fix the upstream.

Network Error — connection refused / DNS / TLS failure. Check the host, port, and certs. In browsers also covers CORS preflight failure.

CORS error in browser only — server is missing Access-Control-Allow-Origin. Axios cannot bypass CORS; fix the server.

Cannot find module 'form-data' — Node-side multipart upload requires form-data; the browser uses the built-in FormData. Install it.

Empty response bodyresponseType: 'stream' returns a stream; you must consume it. With default responseType: 'json', an empty body parses as '' (not null).

AxiosError: Request failed with status code 401 — auth failure. Check the token; in tests, ensure the mock is registered before the call.

maxContentLength size of -1 exceeded — your response exceeded the 100MB default. Increase maxContentLength and maxBodyLength (the latter for outgoing bodies).

When NOT to use this

  • Modern Node + browser code with no interceptor needs. Native fetch works in Node 18+ and all browsers; one less dep.
  • Edge runtimes only. Cloudflare Workers, Deno Deploy, Vercel Edge — all have fetch natively. Axios works with the fetch adapter but adds weight.
  • Bundle-size-critical browser code. A small widget should use ky or fetch. Axios is ~12 KB gzipped, which is huge in that context.
  • Streaming-heavy workloads in Node. undici or got expose richer streaming APIs than axios.
  • Need HTTP/2 push or WebTransport. Axios is HTTP/1.1-focused. Use a lower-level client.

See also

  • JavaScript: fetch — native fetch API, headers, request bodies, abort signals
  • Concept: http — HTTP methods, status codes, headers, content negotiation