What is Axios?
Axios is a promise-based HTTP client library for JavaScript that works seamlessly in both browser and Node.js environments. Unlike the native Fetch API, Axios provides a comprehensive feature set out of the box, making it the preferred choice for developers building modern web applications.
Cross-platform compatibility, automatic JSON transformation, and a rich feature set including request interceptors and automatic CSRF protection make Axios indispensable for enterprise-grade applications.
For development teams building with Next.js, React, or Node.js, Axios provides consistent patterns that scale from prototype to production without requiring architectural changes.
Axios by the Numbers
48M+
Weekly Downloads
105K+
GitHub Stars
IE11+
Browser Support
100%
Promise-Based
Installation and Setup
Getting started with Axios is straightforward. Whether you're working with a modern bundler or need a quick script tag solution, Axios has you covered.
# npm
npm install axios
# yarn
yarn add axios
# pnpm
pnpm add axios<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>import axios from 'axios';
// For tree-shaking optimized bundles
import axios from 'axios/index.mjs';Making HTTP Requests
Axios provides intuitive methods for all HTTP operations. Each method returns a Promise, enabling clean async/await syntax throughout your application.
GET Requests
GET requests retrieve data from a server. Axios simplifies query parameter handling and header configuration.
// Simple GET request
const response = await axios.get('https://api.example.com/users');
// GET with query parameters
const users = await axios.get('https://api.example.com/users', {
params: {
page: 1,
limit: 50,
sort: 'createdAt'
}
});
// GET with custom headers
const privateData = await axios.get('https://api.example.com/private', {
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
}
});POST Requests
POST requests send data to the server for creation. Axios handles JSON and form data seamlessly.
// POST JSON data
const newUser = await axios.post('https://api.example.com/users', {
name: 'John Doe',
email: '[email protected]',
role: 'developer'
});
// POST with form data
const formData = new FormData();
formData.append('name', 'John Doe');
formData.append('avatar', fileInput.files[0]);
const response = await axios.post('https://api.example.com/users', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});PUT and PATCH Requests
PUT replaces entire resources while PATCH performs partial updates. Understanding the distinction is crucial for API design.
// PUT - Complete resource replacement
const updatedUser = await axios.put('https://api.example.com/users/123', {
name: 'Jane Doe',
email: '[email protected]',
role: 'admin'
});
// PATCH - Partial update
const patchedUser = await axios.patch('https://api.example.com/users/123', {
email: '[email protected]' // Only update email
});DELETE Requests
DELETE requests remove resources from the server. Axios also supports request bodies when APIs require them.
// Simple DELETE
await axios.delete('https://api.example.com/users/123');
// DELETE with request body
await axios.delete('https://api.example.com/users/123', {
data: {
reason: 'user_request',
confirm: true
}
});Understanding Responses
Every Axios response contains a rich object with multiple properties for comprehensive data access. This structured response eliminates the need for manual JSON parsing that the Fetch API requires.
const response = await axios.get('https://api.example.com/users');
// Response body data (auto-parsed JSON)
response.data;
// HTTP status code
response.status;
// Status text
response.statusText; // "OK"
// Response headers
response.headers;
// Request configuration that generated this response
response.config;// Extract only what you need
const { data: users, status } = await axios.get('https://api.example.com/users');
if (status === 200) {
console.log(users);
}Error Handling
Robust error handling is essential for production applications. Axios provides detailed error objects that distinguish between server errors, network failures, and request configuration issues.
try {
const response = await axios.get('https://api.example.com/protected');
} catch (error) {
if (error.response) {
// Server responded with error status (4xx, 5xx)
console.log('Server Error:', error.response.status);
console.log('Response Data:', error.response.data);
} else if (error.request) {
// Request made but no response received
console.log('Network Error: No response received');
} else {
// Error setting up the request
console.log('Request Setup Error:', error.message);
}
}| Code | Meaning | Handling Strategy |
|---|---|---|
| 400 | Bad Request | Validate input, show user-friendly message |
| 401 | Unauthorized | Refresh token or redirect to login |
| 403 | Forbidden | Check permissions, show access denied |
| 404 | Not Found | Handle gracefully, show fallback content |
| 500 | Server Error | Retry with backoff, notify monitoring |
Interceptors: The Power Feature
Interceptors are Axios' most powerful feature for cross-cutting concerns like authentication, logging, and error handling. They allow you to modify requests and responses globally without duplicating code across your application.
// Add auth token to every request
axios.interceptors.request.use(
(config) => {
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
// Add request timestamp for performance tracking
config.metadata = { startTime: Date.now() };
return config;
},
(error) => Promise.reject(error)
);// Global response handler
axios.interceptors.response.use(
(response) => {
// Add response time header
const duration = Date.now() - response.config.metadata.startTime;
console.log(`${response.config.url}: ${duration}ms`);
return response;
},
async (error) => {
// Handle 401 globally - attempt token refresh
if (error.response?.status === 401 && !error.config._retry) {
error.config._retry = true;
try {
const refreshToken = localStorage.getItem('refreshToken');
const { data } = await axios.post('/api/refresh-token', {
refreshToken
});
localStorage.setItem('authToken', data.accessToken);
error.config.headers.Authorization = `Bearer ${data.accessToken}`;
return axios(error.config);
} catch (refreshError) {
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);Axios Instances
Creating reusable Axios instances with custom configurations is essential for applications that interact with multiple APIs. Each instance maintains its own interceptors and default settings.
// API instance for main backend
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json'
}
});
// Analytics instance
const analytics = axios.create({
baseURL: 'https://analytics.example.com',
timeout: 5000,
headers: {
'X-Analytics-Key': process.env.ANALYTICS_KEY
}
});
// Apply interceptors to specific instances
api.interceptors.request.use(authInterceptor);
analytics.interceptors.request.use(timingInterceptor);Request Cancellation
Proper request cancellation prevents memory leaks and reduces unnecessary network traffic. This is especially important in React components where users may navigate away before requests complete.
import axios from 'axios';
// Create cancel token source
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
// Make cancellable request
const request = axios.get('/api/users', {
cancelToken: source.token
});
// Cancel the request
source.cancel('Operation cancelled by user');
// Check if request was cancelled
if (axios.isCancel(error)) {
console.log('Request cancelled:', error.message);
}// Modern approach using AbortController
const controller = new AbortController();
const signal = controller.signal;
const response = await axios.get('/api/users', { signal });
// Abort after timeout
setTimeout(() => controller.abort(), 5000);useEffect(() => {
const controller = new AbortController();
const fetchData = async () => {
try {
const response = await axios.get('/api/data', {
signal: controller.signal
});
setData(response.data);
} catch (error) {
if (!axios.isCancel(error)) {
setError(error);
}
}
};
fetchData();
// Cleanup: cancel on unmount
return () => controller.abort();
}, []);Progress Tracking
For file uploads and large data transfers, Axios provides built-in progress callbacks that enable real-time progress indicators in your user interface.
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const response = await axios.post('/api/upload', formData, {
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(`Upload: ${percentCompleted}%`);
setUploadProgress(percentCompleted);
},
onDownloadProgress: (progressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(`Download: ${percentCompleted}%`);
}
});TypeScript Support
Axios includes comprehensive TypeScript definitions out of the box. This enables type-safe API calls, generic response wrappers, and excellent IDE support for your API layer. When combined with proper type definitions and techniques like type casting in TypeScript, you can build robust, maintainable HTTP layers that catch errors at compile time rather than runtime.
import axios, { AxiosResponse } from 'axios';
interface User {
id: number;
name: string;
email: string;
createdAt: string;
}
async function getUser(id: number): Promise<User> {
const response: AxiosResponse<User> = await axios.get(
`https://api.example.com/users/${id}`
);
return response.data;
}
// Generic response wrapper
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
async function fetchApi<T>(url: string): Promise<ApiResponse<T>> {
const response = await axios.get<ApiResponse<T>>(url);
return response.data;
}Best Practices
Implementing these production-ready patterns ensures maintainable, reliable API interactions that scale with your application.
axios.interceptors.response.use(
null,
async (error) => {
if (error.config && !error.config._retry) {
error.config._retry = true;
// Retry on 5xx errors
if (error.response?.status >= 500) {
await new Promise(resolve => setTimeout(resolve, 1000));
return axios(error.config);
}
}
return Promise.reject(error);
}
);const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
timeout: parseInt(process.env.API_TIMEOUT) || 10000
});Comparison with Fetch API
While the native Fetch API is built into browsers, Axios offers significant advantages for production applications. Understanding both helps you choose the right tool for each scenario.
| Feature | Axios | Fetch API |
|---|---|---|
| JSON transformation | Automatic | Manual .json() call |
| Error handling | Throws on 4xx/5xx | Only network errors throw |
| Request timeout | Built-in | Manual AbortController |
| Progress events | Built-in | Limited support |
| Interceptors | Native | Requires wrapper |
| Request cancellation | CancelToken + AbortController | AbortController only |
| Bundle size | ~13KB minified | 0 (native) |
| Browser support | IE11+ | Modern browsers |
| TypeScript | Built-in types | Requires polyfill |
When to Use Axios
- Complex applications requiring interceptors
- Need automatic JSON handling
- Cross-browser compatibility required
- TypeScript projects requiring type safety
When to Use Fetch
- Minimal bundle size critical
- Modern browser support only
- Simple one-off requests
- No dependencies policy
Common Pitfalls and Solutions
Avoid these common mistakes to build more reliable HTTP layers in your applications.
Not Handling Errors
Always wrap requests in try-catch blocks and handle specific error types.
Forgetting to Cancel Requests
Use AbortController in cleanup functions to prevent memory leaks in React components.
Hardcoding URLs
Centralize Axios instances with environment-based configuration.
Ignoring Response Status
Validate response data structure, don't assume 2xx means valid data.
Conclusion
Axios remains the gold standard for HTTP requests in JavaScript applications. Its balance of simplicity and power makes it suitable for everything from rapid prototypes to enterprise applications. By mastering Axios' features--instances, interceptors, cancel tokens, and TypeScript support--you can build robust, maintainable HTTP layers that scale with your application.
The key to success is understanding when to use Axios' advanced features and when to keep things simple. Start with basic requests, add interceptors as cross-cutting concerns emerge, and leverage TypeScript for long-term maintainability. For teams working on web development projects, investing time in mastering Axios pays dividends in code quality and developer productivity.
Sources
- Axios GitHub Repository - Official repository with 105K+ stars
- Generalist Programmer - Axios HTTP Client Complete Guide - Comprehensive tutorial
- LogRocket Blog - Axios in JavaScript - Detailed guide with practical examples
- Apidog - How to Make HTTP Requests with Axios - Modern 2025 guide
- MDN Web Docs - Using Fetch - Native Fetch API reference