DEV Community

Cover image for axios ❌ hurl ✅ — Here's Why I Stopped Using axios in 2026
Ramadan Ahmed
Ramadan Ahmed

Posted on

axios ❌ hurl ✅ — Here's Why I Stopped Using axios in 2026

axios had a great run.

For years it was the HTTP client. You installed it without thinking. You recommended it without question. It just worked.

But it's 2026. Node.js has had native fetch since v18. Cloudflare Workers, Vercel Edge Functions, Deno, and Bun are mainstream. And axios — a 35KB library built around XMLHttpRequest — isn't built for any of that.

I built @firekid/hurl to fix that.


What's wrong with axios?

Let me be specific, because "axios is old" isn't an argument.

1. It doesn't run on edge runtimes.
Cloudflare Workers, Vercel Edge, and Deno don't support Node.js built-ins. axios depends on them. You hit a wall the moment you try to use it outside of a traditional Node.js server.

2. It's 35KB.
For a package that wraps HTTP requests. @firekid/hurl is under 9KB gzipped.

3. No built-in retries.
You either write your own retry logic or reach for axios-retry — another dependency, more config, more maintenance.

4. No request deduplication.
If your app fires the same GET request three times simultaneously, axios makes three network calls. Every time.

5. No in-memory caching.
Out of the box, zero cache support.

It's not that axios is broken. It's that the ecosystem has moved on and axios hasn't.


Enter hurl

npm install @firekid/hurl
Enter fullscreen mode Exit fullscreen mode

Zero dependencies. Full TypeScript support. Under 3KB gzipped. Works on Node.js 18+, Cloudflare Workers, Vercel Edge, Deno, and Bun.

Here's what a real-world usage looks like:

import hurl from '@firekid/hurl'

// Automatic retry with exponential backoff
const res = await hurl.get('https://api.example.com/users', {
  retry: 3,
  timeout: 5000,
  auth: { type: 'bearer', token: process.env.API_TOKEN },
  cache: { ttl: 60000 },
})

console.log(res.data)    // parsed body
console.log(res.timing)  // { start, end, duration }
console.log(res.fromCache) // boolean
Enter fullscreen mode Exit fullscreen mode

That's retries, timeout, auth, and caching — no plugins, no wrappers, no extra packages.


The comparison you actually want

Feature hurl axios ky got
Bundle size ~9KB ~35KB ~5KB ~45KB
Edge runtime support
Built-in retries
In-memory cache
Request deduplication
Auth helpers ⚠️
Interceptors
CommonJS + ESM
Zero dependencies

Things hurl does that axios simply can't

Works on Cloudflare Workers and Vercel Edge

// This just works — no adapter, no polyfill
export default {
  async fetch(request) {
    const res = await hurl.get('https://api.example.com/data')
    return new Response(JSON.stringify(res.data))
  }
}
Enter fullscreen mode Exit fullscreen mode

Retry with full control

await hurl.get('/unstable-endpoint', {
  retry: {
    count: 4,
    delay: 500,
    backoff: 'exponential',
    on: [500, 502, 503, 429],
  }
})
Enter fullscreen mode Exit fullscreen mode

Request deduplication

// Only ONE network request is made — both get the same response
const [a, b] = await Promise.all([
  hurl.get('/users', { deduplicate: true }),
  hurl.get('/users', { deduplicate: true }),
])
Enter fullscreen mode Exit fullscreen mode

In-memory caching with TTL

// Cache for 60 seconds
await hurl.get('/config', { cache: { ttl: 60000 } })
Enter fullscreen mode Exit fullscreen mode

Isolated instances (like axios.create, but better)

const api = hurl.create({
  baseUrl: 'https://api.example.com',
  auth: { type: 'bearer', token: process.env.TOKEN },
  retry: 3,
  timeout: 8000,
})

const adminApi = api.extend({
  headers: { 'x-role': 'admin' }
})
Enter fullscreen mode Exit fullscreen mode

Typed errors — no more error.response?.data

import hurl, { HurlError } from '@firekid/hurl'

try {
  await hurl.get('/protected')
} catch (err) {
  if (err instanceof HurlError) {
    console.log(err.status)     // 401
    console.log(err.data)       // parsed error body
    console.log(err.retries)    // how many times it retried
    console.log(err.type)       // 'HTTP_ERROR' | 'TIMEOUT_ERROR' | 'ABORT_ERROR' ...
  }
}
Enter fullscreen mode Exit fullscreen mode

What about ky and got?

ky is great — but it's browser-first. No proxy support, no Node.js streaming, dropped CommonJS.

got is powerful — but dropped CommonJS in v12, making it incompatible with most existing Node.js projects, and it's 45KB.

@firekid/hurl is the only one that runs everywhere, supports both CJS and ESM, and ships everything you need without external plugins.


Migration from axios takes 5 minutes

// Before
import axios from 'axios'
const res = await axios.get('/users')
console.log(res.data)

// After
import hurl from '@firekid/hurl'
const res = await hurl.get('/users')
console.log(res.data)
Enter fullscreen mode Exit fullscreen mode

The API is intentionally familiar. res.data, res.status, res.headers — it all maps over.


Try it

npm install @firekid/hurl
Enter fullscreen mode Exit fullscreen mode

If this saved you from another axios-retry install, drop a ⭐ on GitHub. And if you find a bug or want a feature, issues are open.


Built by Firekid — feedback welcome.

Top comments (0)