Axios vs Node Fetch
Axios is a batteries-included HTTP client; Node's built-in fetch is the zero-dependency standard. Which one belongs in your codebase.
The short answer
Axios over Node Fetch for most cases. Axios wins for application code because it does the boring work you'd otherwise hand-write around fetch: JSON parsing, real error throwing on 4xx/5xx,.
- Pick Axios if writing application/backend code and want interceptors, automatic JSON, timeouts, and errors that actually throw on bad status codes without ceremony
- Pick Node Fetch if shipping a library, want zero dependencies, or are on the edge/serverless and care about bundle size and using the platform standard
- Also consider: undici directly (Node fetch is undici under the hood) if you want the standard plus connection-pool control; ky if you want a tiny fetch wrapper with retries without Axios's heft.
— Nice Pick, opinionated tool recommendations
The error-handling gap nobody warns you about
This is the line that bites everyone. Node fetch does NOT reject on HTTP 404 or 500 — it resolves happily, and you only discover the failure when you remember to check response.ok and throw yourself. Forget once and a 500 sails through as if it succeeded, corrupting downstream logic silently. Axios throws on any non-2xx by default, hands you error.response.status and the parsed body, and you handle it in a normal try/catch. For a backend talking to flaky third-party APIs, that default is the difference between loud failures and 2am pages. You can replicate Axios's behavior on fetch with a wrapper, but now you're maintaining a wrapper. The whole point of a library is that someone already wrote and tested that wrapper. Axios did. This single behavioral default justifies the dependency for most server code.
Ergonomics: where Axios earns its weight
Axios gives you const { data } = await axios.get(url) — JSON already parsed, no double-await. Fetch makes you await res.json() every single time, which is fine until it's the hundredth time. Axios's real moat is interceptors: attach auth tokens, refresh-on-401, log every request, inject correlation IDs — globally, in one place, instead of threading a wrapper through every call site. It has built-in timeout, baseURL, query-param serialization, and (via axios-retry) retry-with-backoff. Fetch has none of this natively; AbortController for timeouts is verbose and you'll copy-paste the boilerplate forever. If you're building a service that hits multiple APIs with shared auth and observability, Axios is the obvious tool. None of this is magic — it's just code you don't have to write, review, or own.
Where Node fetch is genuinely the better pick
Don't reach for Axios reflexively. Node fetch (stable since Node 18, no flag since 20) is built in: zero dependencies, zero install, zero supply-chain surface, nothing to bump when an advisory drops. For a published library, shipping fetch instead of dragging Axios into every consumer's tree is the courteous, correct choice. On edge runtimes (Cloudflare Workers, Vercel Edge, Deno) fetch IS the platform — Axios's Node adapter doesn't even apply, and bundle size matters. Fetch is the web standard, so the same code runs in the browser and on the server, and your team already knows the API from frontend work. If your needs are 'make a few GET requests and parse JSON,' adding a dependency for that is overkill. The standard exists; use it when the standard is enough.
The honest tradeoff and my call
Axios is ~50KB+ of dependency for behavior you may only partly use, and it's an extra thing to keep patched. Fetch is free but makes you assemble error handling, timeouts, and retries by hand — and teams do that inconsistently across a codebase, which is its own bug factory. The real question isn't 'which is better,' it's 'who writes the glue.' Axios wrote it once, tested it, and ships it. Hand-rolling fetch wrappers means every project reinvents a slightly different, lightly-tested version of Axios. For application and backend code, I pick Axios — the defaults are correct and the interceptor model scales. For libraries and edge runtimes, ship fetch. If you're on the fence and want the standard with a little sugar, ky is the sane middle. But pick deliberately, not by habit.
Quick Comparison
| Factor | Axios | Node Fetch |
|---|---|---|
| Dependencies | External package (~50KB+), must install and keep patched | Built into Node 18+, zero install, zero supply-chain surface |
| Error handling on bad status | Throws automatically on non-2xx with parsed body | Resolves on 404/500; you must check res.ok and throw yourself |
| JSON & ergonomics | Auto-parses to .data, baseURL, param serialization | Manual await res.json() every call, more boilerplate |
| Interceptors / middleware | Built-in request/response interceptors for auth, retry, logging | None native; roll your own wrapper |
| Edge/standard portability | Node adapter; not the native primitive on edge runtimes | Web standard, runs unchanged on browser, Deno, Workers, Edge |
The Verdict
Use Axios if: You're writing application/backend code and want interceptors, automatic JSON, timeouts, and errors that actually throw on bad status codes without ceremony.
Use Node Fetch if: You're shipping a library, want zero dependencies, or are on the edge/serverless and care about bundle size and using the platform standard.
Consider: undici directly (Node fetch is undici under the hood) if you want the standard plus connection-pool control; ky if you want a tiny fetch wrapper with retries without Axios's heft.
Axios vs Node Fetch: FAQ
Is Axios or Node Fetch better?
Axios is the Nice Pick. Axios wins for application code because it does the boring work you'd otherwise hand-write around fetch: JSON parsing, real error throwing on 4xx/5xx, timeouts, retries via interceptors, and request/response middleware. Node fetch is the right call for libraries and dependency-zealot codebases, but in a real backend you will reinvent half of Axios within a month, badly. Pick the one that already shipped that code.
When should you use Axios?
You're writing application/backend code and want interceptors, automatic JSON, timeouts, and errors that actually throw on bad status codes without ceremony.
When should you use Node Fetch?
You're shipping a library, want zero dependencies, or are on the edge/serverless and care about bundle size and using the platform standard.
What's the main difference between Axios and Node Fetch?
Axios is a batteries-included HTTP client; Node's built-in fetch is the zero-dependency standard. Which one belongs in your codebase.
How do Axios and Node Fetch compare on dependencies?
Axios: External package (~50KB+), must install and keep patched. Node Fetch: Built into Node 18+, zero install, zero supply-chain surface. Node Fetch wins here.
Are there alternatives to consider beyond Axios and Node Fetch?
undici directly (Node fetch is undici under the hood) if you want the standard plus connection-pool control; ky if you want a tiny fetch wrapper with retries without Axios's heft.
Axios wins for application code because it does the boring work you'd otherwise hand-write around fetch: JSON parsing, real error throwing on 4xx/5xx, timeouts, retries via interceptors, and request/response middleware. Node fetch is the right call for libraries and dependency-zealot codebases, but in a real backend you will reinvent half of Axios within a month, badly. Pick the one that already shipped that code.
Related Comparisons
Disagree? nice@nicepick.dev