This comparison evaluates six npm packages designed to add automatic retry capabilities to HTTP requests. These tools address transient network failures, server timeouts, and rate limiting by automatically re-sending failed requests based on configurable strategies. While they share a common goal, they differ significantly in their underlying HTTP clients (Axios, Fetch, Request, Superagent), maintenance status, and integration patterns. Some are modern, actively maintained plugins for current standards, while others are legacy solutions tied to deprecated libraries. Understanding these distinctions is critical for building resilient frontend and Node.js applications without introducing technical debt.
Building resilient applications means expecting failure. Networks drop packets, servers timeout, and APIs rate-limit users. To handle these transient errors, developers use retry libraries that automatically re-attempt failed HTTP requests. The JavaScript ecosystem offers several options, but they are not interchangeable. They differ by the HTTP client they support, their maintenance status, and how they integrate into your codebase.
This analysis breaks down six popular packages. We will look at which ones are safe for modern development, which are deprecated, and exactly how to implement them in real scenarios.
Before writing any code, we must address the elephant in the room. Two of the packages in this comparison—requestretry and retry-request—are built on top of the request library.
The request library was officially deprecated in February 2020. It no longer receives security updates or bug fixes. Consequently, you should not use requestretry or retry-request in any new project.
// ❌ LEGACY: Do not use in new projects
const request = require('requestretry');
request({
url: 'https://api.example.com/data',
maxAttempts: 3,
retryDelay: 2000
}, function (err, response, body) {
// Handling logic here
});
Using these libraries forces your application to depend on unmaintained code. If a security vulnerability is discovered in the underlying request package, your application is exposed. For all new development, migrate to solutions based on Axios or the native Fetch API.
For contemporary frontend and Node.js development, the choice is effectively between axios-retry, retry-axios, and fetch-retry. These libraries wrap modern, maintained HTTP clients.
axios-retry vs retry-axios)Axios remains the most popular HTTP client for complex applications due to its rich feature set, including interceptors, request cancellation, and automatic JSON transformation. Two packages add retry logic to Axios: axios-retry and retry-axios.
axios-retry is the dominant choice. It is widely adopted, well-documented, and offers a flexible API for defining retry conditions. It attaches directly to the Axios instance via interceptors.
// ✅ RECOMMENDED: axios-retry
import axios from 'axios';
import axiosRetry from 'axios-retry';
const client = axios.create({ baseURL: 'https://api.example.com' });
axiosRetry(client, {
retries: 3,
retryDelay: (retryCount) => {
return retryCount * 1000; // Linear backoff
},
retryCondition: (error) => {
// Retry on 5xx errors or network errors
return axiosRetry.isNetworkOrIdempotentRequestError(error) || error.response?.status === 503;
}
});
// Usage is transparent; retries happen automatically
client.get('/users');
retry-axios also provides retry functionality for Axios but is less commonly used in the broader community. It follows a similar interceptor pattern but often lacks the extensive configuration options and community examples found in axios-retry.
// ⚠️ ALTERNATIVE: retry-axios
import axios from 'axios';
import { attach } from 'retry-axios';
attach({
axios: axios,
retryConfig: {
retries: 3,
retryDelay: 1000,
statusCodes: [500, 502, 503, 504]
}
});
// Usage
axios.get('/users');
Selection Guideline: Unless you have a specific requirement that axios-retry cannot meet, default to axios-retry. Its larger community ensures better long-term support and more available troubleshooting resources.
fetch-retry)The native fetch API is now available in all modern browsers and recent versions of Node.js (v18+). It is lightweight and standard-compliant but lacks built-in retry logic. fetch-retry fills this gap by wrapping the native function.
This is the best choice for projects aiming to reduce bundle size by avoiding heavy HTTP clients like Axios.
// ✅ MODERN: fetch-retry
import fetchRetry from 'fetch-retry';
// Wrap the native fetch
const fetchWithRetry = fetchRetry(fetch);
fetchWithRetry('https://api.example.com/users', {
retries: 3,
retryDelay: (attempt) => Math.pow(2, attempt) * 1000, // Exponential backoff
retryOn: (attempt, error, response) => {
// Retry if status is 503 or if a network error occurred
if (attempt >= 3) return false;
if (response && response.status === 503) return true;
if (error) return true;
return false;
}
})
.then(response => response.json())
.then(data => console.log(data));
Selection Guideline: Use fetch-retry if you are building modern web apps, serverless functions, or microservices where minimizing dependencies is a priority. It pairs perfectly with node-fetch for older Node.js environments.
superagent-retry)Superagent was once a leading HTTP client, known for its fluent API. While its usage has declined in favor of Axios and Fetch, some legacy enterprise systems still rely on it. superagent-retry is a plugin specifically designed for this client.
// ⚠️ LEGACY MAINTENANCE ONLY: superagent-retry
import request from 'superagent';
import requestRetry from 'superagent-retry';
requestRetry(request);
request
.get('https://api.example.com/users')
.retry(3) // Set retry count
.end((err, res) => {
if (err) throw err;
console.log(res.body);
});
Selection Guideline: Only use superagent-retry if you are maintaining an existing codebase that already uses Superagent. Do not introduce Superagent into a new project; the ecosystem momentum has clearly shifted to Axios and Fetch.
A key differentiator between these libraries is how they handle backoff strategies. Blindly retrying immediately can overwhelm a struggling server. Effective libraries implement exponential backoff—waiting longer between each attempt.
All modern packages discussed (axios-retry, fetch-retry) allow custom delay functions. Here is how they compare in implementation:
In axios-retry:
You define a retryDelay function that receives the retry count.
axiosRetry(axiosClient, {
retryDelay: (retryCount) => {
// Wait 1s, then 2s, then 4s...
return Math.pow(2, retryCount) * 1000;
}
});
In fetch-retry:
The retryDelay option works similarly, accepting the attempt number.
fetchWithRetry(url, {
retryDelay: (attempt) => {
// Wait 1s, then 2s, then 4s...
return Math.pow(2, attempt) * 1000;
}
});
In superagent-retry:
Superagent's plugin often uses a simpler configuration or relies on the underlying library's timeout mechanisms, though custom delays can sometimes be chained.
request
.get(url)
.retry(3, (err, res) => {
if (err) return 2000; // Fixed delay or logic based on error
return 0;
});
Not all errors should trigger a retry. Retrying a 401 Unauthorized or 404 Not Found is useless. You must configure conditions carefully.
axios-retry provides a helper isNetworkOrIdempotentRequestError which automatically handles common safe-to-retry scenarios (like GET requests failing due to network issues).
retryCondition: (error) => {
return axiosRetry.isNetworkOrIdempotentRequestError(error) || error.code === 'ECONNRESET';
}
fetch-retry requires you to manually inspect the response object or catch block, giving you full control but requiring more boilerplate.
retryOn: (attempt, error, response) => {
if (error || (response && response.status >= 500)) {
return true;
}
return false;
}
| Package | Base Client | Maintenance Status | Best Use Case |
|---|---|---|---|
axios-retry | Axios | ✅ Active | Standard choice for Axios projects |
fetch-retry | Fetch API | ✅ Active | Modern, lightweight, dependency-free |
retry-axios | Axios | ⚠️ Low Activity | Alternative Axios interceptor |
superagent-retry | Superagent | ⚠️ Legacy | Maintaining old Superagent codebases |
requestretry | Request | ❌ Deprecated | Do Not Use |
retry-request | Request | ❌ Deprecated | Do Not Use |
For new projects, the decision is straightforward:
axios-retry.fetch-retry.Avoid requestretry and retry-request entirely. They represent a bygone era of JavaScript development and pose unnecessary risks. By choosing actively maintained libraries, you ensure your application remains secure, performant, and easy to debug for years to come.
Choose axios-retry if your project already uses Axios as its primary HTTP client. It is the industry standard for Axios-based retry logic, offering robust exponential backoff, custom retry conditions, and seamless integration via interceptors. It is actively maintained and works in both browser and Node.js environments.
Choose fetch-retry if you are using the native fetch API or node-fetch and want a lightweight, dependency-free solution. It wraps the native fetch function to add retry logic without requiring a full client replacement, making it ideal for modern stacks aiming to minimize bundle size.
Do NOT choose requestretry for new projects. It depends on the request library, which has been officially deprecated since 2020. Using this package introduces significant security risks and technical debt. Migrate to axios-retry or fetch-retry instead.
Choose retry-axios only if you need a very specific, minimal interceptor implementation that differs slightly from axios-retry. However, for most use cases, axios-retry is more feature-complete and better documented. This package is less common and may have a smaller community support footprint.
Do NOT choose retry-request for new projects. Like requestretry, it relies on the deprecated request library. It is strictly legacy software and should be avoided in favor of modern alternatives based on Axios or native Fetch.
Choose superagent-retry only if you are maintaining an existing legacy codebase that relies heavily on Superagent. For new development, prefer axios-retry or fetch-retry, as Superagent has seen significantly reduced adoption compared to Axios and native Fetch in recent years.
Axios plugin that intercepts failed requests and retries them whenever possible.
npm install axios-retry
// CommonJS
// const axiosRetry = require('axios-retry').default;
// ES6
import axiosRetry from 'axios-retry';
axiosRetry(axios, { retries: 3 });
axios.get('http://example.com/test') // The first request fails and the second returns 'ok'
.then(result => {
result.data; // 'ok'
});
// Exponential back-off retry delay between requests
axiosRetry(axios, { retryDelay: axiosRetry.exponentialDelay });
// Liner retry delay between requests
axiosRetry(axios, { retryDelay: axiosRetry.linearDelay() });
// Custom retry delay
axiosRetry(axios, { retryDelay: (retryCount) => {
return retryCount * 1000;
}});
// Works with custom axios instances
const client = axios.create({ baseURL: 'http://example.com' });
axiosRetry(client, { retries: 3 });
client.get('/test') // The first request fails and the second returns 'ok'
.then(result => {
result.data; // 'ok'
});
// Allows request-specific configuration
client
.get('/test', {
'axios-retry': {
retries: 0
}
})
.catch(error => { // The first request fails
error !== undefined
});
Note: Unless shouldResetTimeout is set, the plugin interprets the request timeout as a global value, so it is not used for each retry but for the whole request lifecycle.
| Name | Type | Default | Description |
|---|---|---|---|
| retries | Number | 3 | The number of times to retry before failing. 1 = One retry after first failure |
| retryCondition | Function | isNetworkOrIdempotentRequestError | A callback to further control if a request should be retried. By default, it retries if it is a network error or a 5xx error on an idempotent request (GET, HEAD, OPTIONS, PUT or DELETE). |
| shouldResetTimeout | Boolean | false | Defines if the timeout should be reset between retries |
| retryDelay | Function | function noDelay() { return 0; } | A callback to further control the delay in milliseconds between retried requests. By default there is no delay between retries. Another option is exponentialDelay (Exponential Backoff) or linearDelay. The function is passed retryCount and error. |
| onRetry | Function | function onRetry(retryCount, error, requestConfig) { return; } | A callback to notify when a retry is about to occur. Useful for tracing and you can any async process for example refresh a token on 401. By default nothing will occur. The function is passed retryCount, error, and requestConfig. |
| onMaxRetryTimesExceeded | Function | function onMaxRetryTimesExceeded(error, retryCount) { return; } | After all the retries are failed, this callback will be called with the last error before throwing the error. |
| validateResponse | Function | null | null | A callback to define whether a response should be resolved or rejected. If null is passed, it will fallback to the axios default (only 2xx status codes are resolved). |
Clone the repository and execute:
npm test
git clone https://github.com/softonic/axios-retry.gitgit checkout -b feature/my-new-featuregit commit -am 'Added some feature'npm run buildgit push origin my-new-feature