Skip to content

What is Axios? A Complete Guide to the JavaScript HTTP Client for Beginners

The Problem

I’ve been working on JavaScript projects for a while, and I keep seeing this axios import everywhere:

common-import.js
import axios from 'axios';

But what exactly is Axios? Why do so many projects use it instead of the built-in fetch? I asked this question when I was new to web development, and I’ll explain what I learned.

What Axios Actually Is

Axios is a promise-based HTTP client for JavaScript that runs in both the browser and Node.js. Think of it as a tool that lets your app “talk to the internet” to fetch or send data.

Here’s the simplest way to use it:

basic-request.js
// Get user data from an API
axios.get('https://api.example.com/users/1')
.then(response => {
console.log(response.data); // The actual data
})
.catch(error => {
console.error(error);
});

That’s it. One line to make a request, automatic JSON parsing, and proper error handling.

Why I Prefer Axios Over fetch

When I started learning JavaScript, I used fetch because it’s built into the browser. But I quickly ran into issues that made me switch to Axios.

Issue 1: Manual JSON Parsing with fetch

With fetch, I always have to call response.json():

fetch-example.js
// Using fetch - two steps to get data
fetch('https://api.example.com/users/1')
.then(response => response.json()) // Step 1: Parse JSON manually
.then(data => {
console.log(data); // Step 2: Use the data
})
.catch(error => {
console.error(error);
});

With Axios, JSON parsing happens automatically:

axios-example.js
// Using axios - one step to get data
axios.get('https://api.example.com/users/1')
.then(response => {
console.log(response.data); // Already parsed as JSON
});

This matters because I’ve forgotten to call response.json() more times than I can count.

Issue 2: fetch Doesn’t Reject on HTTP Errors

This one surprised me. When the server returns a 404 or 500 error, fetch still resolves the promise:

fetch-error-behavior.js
// fetch resolves even on 404!
fetch('https://api.example.com/nonexistent')
.then(response => {
// This runs even when status is 404
if (!response.ok) {
throw new Error('Not found'); // Manual check required
}
return response.json();
})
.catch(error => {
console.error(error);
});

I have to manually check response.ok every time. With Axios, it rejects the promise automatically:

axios-error-behavior.js
// axios rejects on 4xx/5xx automatically
axios.get('https://api.example.com/nonexistent')
.then(response => {
console.log(response.data);
})
.catch(error => {
// This runs automatically on 404/500
console.error(error.response.status); // 404
});

Issue 3: No Built-in Timeout in fetch

With fetch, if a request hangs, there’s no built-in timeout. I have to use AbortController:

fetch-with-timeout.js
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
fetch('https://api.example.com/users', {
signal: controller.signal
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
if (error.name === 'AbortError') {
console.error('Request timed out');
}
})
.finally(() => clearTimeout(timeoutId));

That’s a lot of code for a simple timeout. Axios handles this natively:

axios-with-timeout.js
axios.get('https://api.example.com/users', {
timeout: 5000 // 5 second timeout
})
.then(response => console.log(response.data))
.catch(error => {
if (error.code === 'ECONNABORTED') {
console.error('Request timed out');
}
});

The Key Features That Make Axios Useful

Beyond the basics I showed above, here are the features I use most often:

Request and Response Interceptors

Interceptors let me modify requests before they’re sent and responses before they’re processed. I use this for adding authentication headers:

interceptor-setup.js
// Add auth token to every request
axios.interceptors.request.use(config => {
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Handle 401 errors globally
axios.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
// Redirect to login page
window.location.href = '/login';
}
return Promise.reject(error);
}
);

This means I don’t have to add Authorization headers to every single request manually.

Concurrent Requests

When I need to fetch data from multiple endpoints at once, Promise.all handles this cleanly:

concurrent-requests.js
function getUserData(userId) {
return axios.get(`https://api.example.com/users/${userId}`);
}
function getUserPosts(userId) {
return axios.get(`https://api.example.com/users/${userId}/posts`);
}
// Fetch both at the same time
Promise.all([getUserData(1), getUserPosts(1)])
.then(axios.spread((userResponse, postsResponse) => {
console.log('User:', userResponse.data);
console.log('Posts:', postsResponse.data);
}));

Cancel Token Support

I can cancel requests when users navigate away from a page:

cancel-request.js
const CancelToken = axios.CancelToken;
let cancel;
axios.get('https://api.example.com/search', {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
});
// Cancel the request when user leaves the page
cancel('User navigated away');

Progress Monitoring for File Uploads

When uploading files, I can show progress to users:

upload-with-progress.js
axios.post('https://api.example.com/upload', formData, {
onUploadProgress: progressEvent => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(`Upload progress: ${percentCompleted}%`);
}
});

A Side-by-Side Comparison

Here’s how the two approaches compare:

axios-vs-fetch-comparison.txt
Feature | Axios | fetch
--------------------|------------------------|----------------------
JSON parsing | Automatic | Manual (response.json())
Error handling | Rejects on 4xx/5xx | Resolves on all HTTP codes
Timeout | Built-in (timeout: ms) | AbortController required
Interceptors | Yes | No
Request cancellation| CancelToken | AbortController
Progress monitoring | onUploadProgress | No
Browser support | All browsers + Node.js | Modern browsers only

When I Still Use fetch

Despite preferring Axios, I sometimes use fetch:

  1. When I don’t want to add an extra dependency
  2. For simple one-off requests where interceptors aren’t needed
  3. When working in environments where I can’t install packages

But for most projects, Axios saves me time and prevents common mistakes.

How to Install Axios

If you’re using npm:

install-axios.sh
npm install axios

Or with yarn:

install-axios-yarn.sh
yarn add axios

For browser-only projects, you can include it via CDN:

axios-cdn.html
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

Axios supports all standard HTTP methods:

http-methods.js
// GET - Fetch data
axios.get('/api/users');
// POST - Create new data
axios.post('/api/users', { name: 'John', email: '[email protected]' });
// PUT - Update existing data (full replacement)
axios.put('/api/users/1', { name: 'John Updated' });
// PATCH - Partial update
axios.patch('/api/users/1', { email: '[email protected]' });
// DELETE - Remove data
axios.delete('/api/users/1');

The method names match REST API conventions, which makes the code easy to read.

Summary

In this post, I explained what Axios is and why I use it instead of fetch for most HTTP requests. Axios handles JSON parsing automatically, rejects promises on HTTP errors, has built-in timeout support, and provides interceptors for global request/response handling. The key takeaway is that Axios removes the friction I experience with fetch, letting me focus on my app logic instead of boilerplate code.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments