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
npm install axios
Output: added axios to dependencies
pnpm add axios
Output: added 1 package, linked from store
yarn add axios
Output: added axios
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
fetchbecomes 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
@typesinstall. - 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 backoffaxios-mock-adapter— intercept and stub requests in testsaxios-cache-interceptor— caching layer on top of axiosform-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
| Package | Trade-off |
|---|---|
native fetch | Built into Node 18+ and all browsers. No deps. More boilerplate (no auto-JSON, no interceptors). |
ky | Tiny fetch wrapper. ESM-only. Modern API; smaller bundle than axios. |
got | Powerful Node-only client. Streams, retries, hooks. Not for browsers. |
undici | Node's HTTP/1.1 + HTTP/2 client under the hood of fetch. Lower-level. |
node-fetch | Polyfill of fetch for old Node. Largely obsolete now that Node ships fetch. |
@tanstack/query | Not an HTTP client — a cache around any client. Pair with axios or fetch. |
Real-world recipes
GET with timeout and JSON
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
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.
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
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
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
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
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/httpsAgentwithkeepAlive: trueso connections are reused across requests in a long-lived process. - Edge runtimes (Cloudflare Workers, Vercel Edge). Axios's adapter expects Node's
httpmodule 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 onNODE_ENV !== 'production'. - Proxy support.
httpsAgent: new HttpsProxyAgent(process.env.HTTPS_PROXY)for corporate proxies. Axios'sproxyconfig 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.createcall 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.stringifyoverhead twice. Pass an object asdataand axios stringifies once; passing a pre-stringified string adds nothing but bytes. - Connection pooling. A keep-alive
httpsAgentcuts TLS handshake cost dramatically. Without it each request does a full handshake. - Bundle size in browsers.
axiosis ~30 KB minified, ~12 KB gzipped. For browser bundles where every KB matters, preferky(~6 KB) or nativefetch.
Version migration guide
0.x → 1.x (the only major break)
Most code keeps working — the changes are around edge cases.
| Area | 0.x | 1.x |
|---|---|---|
| Default export | CJS default | Named ESM + dual CJS |
transformRequest / transformResponse | Could be a single function | Must be an array |
paramsSerializer | Function | Object with encode / serialize keys (function form still supported) |
| Form data | Manual handling | FormData auto-detected and serialised |
| Cancellation | CancelToken only | AbortSignal (Web standard) + CancelToken kept for back-compat |
| TypeScript | Less strict generics | Generics on response data tightened |
Before (0.x):
import axios from "axios";
const source = axios.CancelToken.source();
axios.get("/x", { cancelToken: source.token });
source.cancel("user navigated away");
After (1.x):
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:
- Bump to
axios@1.x. Most code compiles unchanged. - Replace
CancelTokenwithAbortController(kept working but is now legacy). - If using a custom
paramsSerializer, verify the object form. - Check that
transformRequest/transformResponseare arrays (a single function silently does the wrong thing in 1.x). - 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
formToJSONhelper 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
baseURLwas 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\nin header values, but be defensive. - TLS verification. Never disable in production.
rejectUnauthorized: falsedefeats HTTPS entirely. - Interceptors execute in user code. A logging interceptor that prints
config.headersto 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
maxContentLengthandmaxBodyLength.
Testing & CI integration
Mock with axios-mock-adapter
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
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
| Package | Role |
|---|---|
axios-retry | Retry transient failures with backoff |
axios-mock-adapter | Test stub layer |
axios-cache-interceptor | In-memory / persistent response cache |
axios-rate-limit | Token-bucket rate limiting |
@nestjs/axios | Nest.js wrapper for DI containers |
zod | Validate response shapes at runtime |
pino-axios | Logging 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 body — responseType: '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
fetchworks in Node 18+ and all browsers; one less dep. - Edge runtimes only. Cloudflare Workers, Deno Deploy, Vercel Edge — all have
fetchnatively. Axios works with the fetch adapter but adds weight. - Bundle-size-critical browser code. A small widget should use
kyorfetch. Axios is ~12 KB gzipped, which is huge in that context. - Streaming-heavy workloads in Node.
undiciorgotexpose 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