How to Retry Failed Requests in Axios
Implementing a retry mechanism for failed HTTP requests in Axios
ensures your application can recover gracefully from temporary network
drops, rate limits, and transient server errors. This article outlines
the essential steps to configure automatic retries in Axios using both
the popular axios-retry plugin for a production-ready
solution and custom Axios interceptors for a lightweight,
dependency-free approach.
Method 1:
Using the axios-retry Plugin (Recommended)
The most robust way to handle retries is with the official
axios-retry library, which provides built-in support for
exponential backoff, custom retry conditions, and retry delays.
Step 1: Install the Package
Install both Axios and the axios-retry package via your
package manager:
npm install axios axios-retryStep 2: Configure the Plugin on an Axios Instance
Create an Axios instance and attach the retry configuration using
axiosRetry:
import axios from 'axios';
import axiosRetry from 'axios-retry';
const apiClient = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
});
// Configure retry behavior
axiosRetry(apiClient, {
retries: 3, // Number of retry attempts
retryDelay: axiosRetry.exponentialDelay, // Exponential backoff (e.g., 100ms, 200ms, 400ms)
retryCondition: (error) => {
// Retry on standard network errors or 5xx server errors
return (
axiosRetry.isNetworkOrIdempotentRequestError(error) ||
error.response?.status === 429 // Also retry on rate limits
);
},
onRetry: (retryCount, error, requestConfig) => {
console.log(`Retry attempt #${retryCount} for URL: ${requestConfig.url}`);
},
});
export default apiClient;Method 2: Manual Implementation with Axios Interceptors
If you prefer not to install external dependencies, you can implement retry logic manually using Axios response interceptors.
Step 1: Create an Axios Instance
Define your base instance and default configuration settings:
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
});Step 2: Attach a Response Interceptor
Use interceptors.response.use to capture errors, track
retry counts on the request configuration object, and resend the request
when appropriate:
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
const { config } = error;
// Do not retry if config is missing or retries are not enabled
if (!config || !config.retry) {
return Promise.reject(error);
}
// Set retry state
config.__retryCount = config.__retryCount || 0;
// Check if max retries have been reached
if (config.__retryCount >= config.retry) {
return Promise.reject(error);
}
// Only retry on network errors or 5xx server status codes
const shouldRetry =
!error.response || (error.response.status >= 500 && error.response.status <= 599);
if (!shouldRetry) {
return Promise.reject(error);
}
// Increment retry count
config.__retryCount += 1;
// Calculate exponential delay
const delay = config.retryDelay || 1000;
const backoff = delay * Math.pow(2, config.__retryCount - 1);
await new Promise((resolve) => setTimeout(resolve, backoff));
// Re-execute the request
return apiClient(config);
}
);Step 3: Trigger Requests with Retry Options
Pass custom retry parameters directly inside your request config:
apiClient.get('/data', {
retry: 3, // Retry up to 3 times
retryDelay: 1000 // Base delay of 1 second
})
.then(response => console.log(response.data))
.catch(error => console.error('Request failed after retries:', error.message));Essential Best Practices
- Retry Idempotent Requests Only: Automatically retry
GET,PUT,DELETE, andHEADrequests. Be cautious when retrying non-idempotentPOSTrequests to prevent duplicate data creation. - Implement Exponential Backoff: Avoid immediate retries, as they can overwhelm recovering servers. Adding a progressive delay (e.g., 1s, 2s, 4s) gives the target service time to recover.
- Limit Maximum Retries: Cap retry attempts (typically between 2 and 4 attempts) to prevent indefinite hanging in the client application.