axios-retry and retry-axios are both utilities designed to add automatic retry capabilities to the popular axios HTTP client. They address transient network failures, such as temporary connection drops or 5xx server errors, by intercepting failed requests and re-sending them based on configurable policies. While they share the same goal, they differ significantly in their implementation strategy: axios-retry wraps the axios instance with a custom interceptor, whereas retry-axios attaches directly to the axios interceptor system. Understanding these architectural differences is crucial for maintaining clean request pipelines in production applications.
Both axios-retry and retry-axios solve the same problem: making HTTP requests more resilient by automatically retrying failed calls. In distributed systems, transient errors like network blips or temporary server overloads are common. Instead of failing immediately, your application can recover by trying again. However, the way these two libraries inject this behavior into axios differs, affecting how you configure and maintain your network layer.
The core architectural difference lies in how they hook into axios.
axios-retry acts as a wrapper that initializes a specific interceptor for a given axios instance. You explicitly call the setup function and pass the instance you want to protect. This makes it clear which instances have retry logic enabled.
// axios-retry: Explicit instance setup
import axios from 'axios';
import axiosRetry from 'axios-retry';
const client = axios.create();
// Apply retry logic specifically to this client
axiosRetry(client, {
retries: 3,
retryDelay: axiosRetry.exponentialDelay
});
retry-axios attaches itself directly to the axios interceptor stack. It often targets the global axios instance or requires you to manage the interceptor ID manually if you want to remove it later. This approach is slightly more implicit.
// retry-axios: Direct interceptor attachment
import axios from 'axios';
import retry from 'retry-axios';
// Attach to the global axios instance
retry.attach();
// Or attach to a specific instance by managing interceptors
const client = axios.create();
const interceptorId = client.interceptors.response.use(
null,
retry.createInterceptor({ maxRetries: 3 })
);
Handling the time between retries is critical to avoid overwhelming a struggling server. Both libraries support custom delay functions, but their default offerings vary.
axios-retry provides built-in helper functions for common delay strategies, such as exponential backoff. This reduces boilerplate code for standard use cases.
// axios-retry: Built-in exponential delay
import axiosRetry from 'axios-retry';
axiosRetry(client, {
retries: 3,
// Uses a helper provided by the library
retryDelay: axiosRetry.exponentialDelay
});
retry-axios expects you to define the delay logic more manually within the configuration object, offering flexibility but requiring more setup for standard patterns.
// retry-axios: Manual delay configuration
import retry from 'retry-axios';
retry.createInterceptor({
maxRetries: 3,
// You define the delay calculation
retryDelay: (retryCount) => {
return Math.pow(2, retryCount) * 1000;
}
});
Retrying every error is often a bad idea. For example, retrying a 401 Unauthorized error usually won't help unless you refresh the token first. Both libraries allow you to define conditions, but the API shape differs.
axios-retry uses a retryCondition callback that receives the error object. You can inspect the response status or the error code to decide.
// axios-retry: Condition based on error object
axiosRetry(client, {
retryCondition: (error) => {
// Retry only on network errors or 5xx status codes
return error.code === 'ECONNABORTED' ||
(error.response && error.response.status >= 500);
}
});
retry-axios handles this through the interceptor logic, often requiring you to check the response status within the retry configuration or the interceptor itself.
// retry-axios: Condition within interceptor config
retry.createInterceptor({
maxRetries: 3,
// Filter which errors trigger a retry
shouldRetry: (error) => {
return error.response ? error.response.status >= 500 : true;
}
});
Retrying non-idempotent requests (like POST) can cause duplicate data (e.g., charging a user twice). Safe retry logic should ideally skip methods that change state unless explicitly allowed.
axios-retry includes a built-in check for idempotent methods by default. It will typically only retry GET, HEAD, OPTIONS, PUT, and DELETE unless you override this behavior.
// axios-retry: Default idempotency check
axiosRetry(client, {
retries: 3,
// Automatically skips POST/ PATCH unless configured otherwise
retryCondition: axiosRetry.isNetworkOrIdempotentRequestError
});
retry-axios does not enforce idempotency checks by default in the same explicit manner. You must implement the logic to check error.config.method yourself to ensure safety.
// retry-axios: Manual idempotency check
retry.createInterceptor({
maxRetries: 3,
shouldRetry: (error) => {
const method = error.config?.method?.toLowerCase();
const safeMethods = ['get', 'put', 'delete', 'head', 'options'];
return safeMethods.includes(method);
}
});
When choosing a dependency for critical infrastructure like networking, maintenance status matters.
axios-retry is generally recognized as the more popular choice in the community. It is frequently updated to remain compatible with new versions of axios and TypeScript definitions are well-maintained. This makes it a safer bet for long-term projects.
retry-axios is a valid tool but has historically seen less frequent updates. While it still functions, teams might encounter more friction when upgrading axios major versions compared to axios-retry.
| Feature | axios-retry | retry-axios |
|---|---|---|
| Integration | Wrapper function for instances | Direct interceptor attachment |
| Delay Helpers | Built-in (e.g., exponentialDelay) | Manual implementation required |
| Idempotency | Built-in default checks | Manual implementation required |
| Configuration | Object passed to wrapper | Object passed to interceptor creator |
| Community Adoption | High | Moderate |
axios-retry is the pragmatic choice for most teams π§°. Its built-in safety features (like idempotency checks) and helper functions reduce the risk of configuration errors. It treats retry logic as a distinct concern that you apply to specific clients, which aligns well with modular architecture.
retry-axios is a lightweight alternative π§ for developers who want direct control over the interceptor chain and prefer to build their own safety checks from scratch. It works well but requires more vigilance to ensure you aren't accidentally retrying unsafe operations.
Final Thought: For production applications where reliability is key, axios-retry offers a more robust out-of-the-box experience. Its explicit API and safety defaults make it easier to reason about during code reviews and debugging sessions.
Choose axios-retry if you want a widely adopted, standalone utility that works with both axios instances and the global axios object. It is ideal for projects that require flexible retry conditions (like retrying only on specific status codes) and need explicit control over the retry count and delay logic without modifying the core axios configuration globally.
Choose retry-axios if you prefer a lightweight solution that integrates directly into axios's interceptor chain without wrapping the instance. It is suitable for applications that want minimal configuration overhead and are comfortable with a more direct attachment to the axios module, though it has seen less frequent maintenance updates compared to its counterpart.
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