DEV Community

Cover image for Axios vs Fetch: Which One Should You Choose for Your Project
Arnab Chatterjee for CodeParrot

Posted on • Originally published at codeparrot.ai

Axios vs Fetch: Which One Should You Choose for Your Project

Introduction

In web development, the debate between Axios vs fetch revolves around making HTTP requests, essential for communication between a browser and server. Whether you're fetching data, submitting forms, or interacting with APIs, HTTP requests keep web applications dynamic. Developers often rely on either fetch(), a built-in browser feature, or the third-party library Axios.

Both Axios and fetch() handle common HTTP requests like GET, POST, PUT, and DELETE but have distinct advantages. Axios is popular for its simplicity and powerful features, while fetch() is lightweight and built into browsers, avoiding external dependencies.

This blog will compare Axios vs fetch, highlighting their key differences, strengths, and weaknesses with practical examples, helping you choose the right tool for your project.

Core Differences Between Axios and fetch()

When deciding between Axios vs fetch, it's important to understand their fundamental differences, starting from syntax and setup to data handling and backward compatibility. Below, we’ll explore the key contrasts between the two to help you navigate your decision.

1. Basic Syntax and Setup

One of the main distinctions between Axios and fetch() is the simplicity of their syntax. Here’s a quick look at how a simple HTTP request looks using both methods:

Axios Example:

axios.get('https://jsonplaceholder.typicode.com/posts')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error('Error:', error);
  });
Enter fullscreen mode Exit fullscreen mode

fetch() Example:

fetch('https://jsonplaceholder.typicode.com/posts')
  .then(response => response.json())
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error('Error:', error);
  });
Enter fullscreen mode Exit fullscreen mode

In Axios, the response data is automatically parsed, and the data object can be accessed directly. With fetch(), you need to manually parse the response by calling response.json(), making Axios more concise for standard operations.

2. Data Handling, JSON Parsing, and Simplicity

Another key difference in the Axios vs fetch discussion revolves around data handling:

  • Automatic JSON Parsing: Axios automatically handles JSON parsing, converting both the request and response data into JSON by default. This is convenient when working with JSON APIs, as it saves you from manually stringifying or parsing data. In contrast, fetch() requires explicit handling of both parsing and stringification, making it slightly more verbose.

Axios Example (Data Handling):

  axios.post('https://jsonplaceholder.typicode.com/posts', {
    title: 'Post Title',
    body: 'Post Content',
  })
  .then(response => console.log(response.data));
Enter fullscreen mode Exit fullscreen mode

fetch() Example (Data Handling):

  fetch('https://jsonplaceholder.typicode.com/posts', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      title: 'Post Title',
      body: 'Post Content'
    })
  })
  .then(response => response.json())
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode
  • Error Handling: In Axios, HTTP errors are automatically handled, and any response with a status code outside the 2xx range triggers the catch block. This means Axios treats server errors (like 404 or 500) as exceptions, making error management more intuitive. In contrast, fetch() only rejects on network failures and still resolves for server errors. You'll need to check the response.ok property manually for handling errors.

fetch() Example (Error Handling):

  fetch('https://jsonplaceholder.typicode.com/invalid-endpoint')
    .then(response => {
      if (!response.ok) {
        throw new Error('Server Error');
      }
      return response.json();
    })
    .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

3. Backward Compatibility

One significant advantage of Axios is its support for older browsers. Axios uses XMLHttpRequest under the hood, allowing it to function even in environments like Internet Explorer 11. This makes it an excellent choice for projects requiring broad browser compatibility without additional configuration.

On the other hand, fetch() is a modern API that only works in more recent browsers—specifically, Chrome 42+, Firefox 39+, Edge 14+, and Safari 10.3+. If backward compatibility is essential and you still prefer using fetch(), you can use a polyfill:

Using a fetch() Polyfill:

npm install whatwg-fetch --save
Enter fullscreen mode Exit fullscreen mode

Setup Example with Polyfill:

import 'whatwg-fetch';
fetch('https://jsonplaceholder.typicode.com/posts')
  .then(response => response.json())
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

In this scenario, whatwg-fetch allows fetch() to work in older browsers by emulating the native API. However, adding a polyfill increases the overall bundle size, which might be a drawback for performance-sensitive applications.

Axios vs fetch differ significantly in syntax, data handling, and compatibility. Axios simplifies common tasks like JSON parsing and error handling, making it appealing for rapid development. However, fetch()’s native availability in browsers makes it a strong, lightweight option if you're comfortable handling JSON manually and don’t require support for outdated browsers.

Ease of Use and Developer Experience

When it comes to developer experience, the debate between Axios vs fetch often revolves around how easy they are to use for common and complex scenarios. Here's a breakdown of how both fare in terms of simplicity and flexibility.

1. Simplicity of Axios for Common Use Cases

Axios is designed to make HTTP requests simpler and more intuitive. It provides a concise and developer-friendly API that’s easy to set up, especially for standard use cases like GET and POST requests:

Example of a Simple GET Request Using Axios:

axios.get('https://jsonplaceholder.typicode.com/posts')
  .then(response => console.log(response.data))
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

In just a few lines, Axios handles the entire request-response cycle, including JSON parsing and error management. It automatically converts the response into a JavaScript object, making it easy to interact with data.

2. Verbosity of fetch() for Edge Cases

While fetch() is straightforward for basic requests, it becomes more verbose when handling complex scenarios, such as setting timeouts or managing errors:

Example of Handling a Timeout Using fetch():

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);

fetch('https://jsonplaceholder.typicode.com/posts', {
  signal: controller.signal
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    if (error.name === 'AbortError') {
      console.error('Request timed out');
    } else {
      console.error('Error:', error);
    }
  });
Enter fullscreen mode Exit fullscreen mode

In this example, managing a timeout requires additional code to set up an AbortController. While this makes fetch() flexible, it requires more boilerplate code compared to Axios’ built-in timeout configuration.

3. Concise Syntax of Axios vs. Flexibility of fetch()

  • Axios' Concise Syntax:

    Axios’ syntax is designed to reduce boilerplate, making it easier to handle requests with fewer lines of code. It automatically transforms JSON, simplifies error handling, and offers built-in features like request cancellation and interceptors, which streamline development. This makes it ideal for projects where quick and efficient HTTP interactions are crucial.

  • fetch()’s Flexibility:

    On the other hand, fetch() offers a more flexible and modular approach. It doesn't impose any default behavior, giving developers full control over the request and response cycle. While this requires more manual handling, it also provides the flexibility to implement custom solutions tailored to specific needs.

Performance Considerations

Choosing between Axios vs fetch often comes down to performance needs and the specific requirements of your project.

1. Suitability Based on Performance Requirements

  • Simple Requests:

    For basic data fetching, fetch() is typically more suitable. It’s a lightweight, built-in option that reduces bundle size since it doesn’t rely on external dependencies.

  • Complex Interactions:

    Axios excels in complex scenarios where you need features like interceptors, custom headers, and error handling. These built-in tools can save development time in larger applications, making Axios a better choice for enterprise-level projects.

2. Network Latency and Response Handling

  • Network Latency:

    There's no significant difference in raw speed between Axios and fetch(), as both rely on similar underlying technologies. Axios may introduce slight overhead due to its features, but this is often negligible for most use cases.

  • Response Handling:

    Axios simplifies JSON handling, automatically parsing responses, while fetch() requires manual parsing with response.json(). This makes Axios slightly faster in terms of development time for JSON-heavy applications.

3. Scenarios for Choosing Axios vs fetch()

  • When Axios is Overkill:

    If your project involves simple requests and minimal data handling, fetch()’s native, no-frills approach is ideal. Avoid the extra weight of Axios for lightweight applications.

  • When fetch() Needs Help:

    For applications that require centralized error handling, retries, or complex headers, fetch() can become cumbersome. In these cases, Axios provides a more streamlined solution without the need for extensive custom code.

By understanding these performance aspects, you can decide between Axios vs fetch based on the complexity and scale of your project.

Feature Comparison for Axios vs Fetch

To fully understand the pros and cons of Axios vs fetch, let’s explore their key features with practical examples:

1. Automatic Data Transformation

Axios automatically handles JSON transformation, converting request payloads and responses without additional code:

Axios Example (Automatic JSON Handling):

axios.post('https://jsonplaceholder.typicode.com/posts', {
  title: 'Axios Post',
  content: 'Axios makes it simple!'
})
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

In Axios, JSON is automatically parsed in both the request and response, simplifying the process.

fetch() Example (Manual JSON Parsing):

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'fetch Post',
    content: 'fetch requires manual handling.'
  })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

With fetch(), you need to manually JSON.stringify() data before sending it and call response.json() to parse the response, adding a bit more complexity.

2. Timeout Management

Handling timeouts can be a challenge with HTTP requests. Axios makes it simple with a built-in timeout property:

Axios Example (Built-in Timeout):

axios.get('https://jsonplaceholder.typicode.com/posts', { timeout: 5000 })
  .then(response => console.log(response.data))
  .catch(error => console.error('Error:', error)); // Automatically catches timeout errors
Enter fullscreen mode Exit fullscreen mode

In Axios, setting a timeout is as simple as adding a timeout configuration.

fetch() Example (Using AbortController for Timeout):

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);

fetch('https://jsonplaceholder.typicode.com/posts', {
  signal: controller.signal
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    if (error.name === 'AbortError') {
      console.error('Request timed out');
    } else {
      console.error('Error:', error);
    }
  });
Enter fullscreen mode Exit fullscreen mode

Using fetch(), timeouts require additional steps with AbortController, making it less straightforward compared to Axios.

3. Error Handling

Error handling is another area where Axios shines with built-in categorization:

Axios Example (Error Categorization):

axios.get('https://jsonplaceholder.typicode.com/invalid-endpoint')
  .then(response => console.log(response.data))
  .catch(error => {
    if (error.response) {
      console.error('Server Error:', error.response.status);
    } else if (error.request) {
      console.error('Network Error:', error.request);
    } else {
      console.error('Unknown Error:', error.message);
    }
  });
Enter fullscreen mode Exit fullscreen mode

Axios categorizes errors into response, request, and unknown, making debugging easier.

fetch() Example (Manual Error Handling):

fetch('https://jsonplaceholder.typicode.com/invalid-endpoint')
  .then(response => {
    if (!response.ok) {
      throw new Error(`Server Error: ${response.status}`);
    }
    return response.json();
  })
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

With fetch(), server errors need to be manually checked using response.ok, as it doesn’t reject promises for non-2xx status codes by default.

4. HTTP Interceptors

Interceptors allow global handling of requests and responses, which is natively supported by Axios:

Axios Example (Global Request Interceptor):

axios.interceptors.request.use(config => {
  config.headers['Authorization'] = 'Bearer token';
  console.log('Request Interceptor: Adding Authorization Header');
  return config;
});
Enter fullscreen mode Exit fullscreen mode

Axios makes it simple to add headers or log information before sending requests.

fetch() Example (Custom Interceptor Implementation):

const originalFetch = fetch;
window.fetch = async (...args) => {
  console.log('Custom Interceptor: Adding Authorization Header');
  const [url, options] = args;
  options.headers = {
    ...options.headers,
    'Authorization': 'Bearer token'
  };
  return originalFetch(url, options);
};
Enter fullscreen mode Exit fullscreen mode

fetch() does not have native interceptors, but you can mimic the behavior by overwriting the global fetch method.

Advanced Use Cases

1. Simultaneous Requests

Handling multiple requests is common in web development, and both Axios and fetch() have their ways:

Axios Example (Simultaneous Requests Using axios.all):

axios.all([
  axios.get('https://jsonplaceholder.typicode.com/posts/1'),
  axios.get('https://jsonplaceholder.typicode.com/posts/2')
])
.then(axios.spread((response1, response2) => {
  console.log('Response 1:', response1.data);
  console.log('Response 2:', response2.data);
}))
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

Axios provides axios.all() and axios.spread() for handling simultaneous requests cleanly.

fetch() Example (Simultaneous Requests Using Promise.all):

Promise.all([
  fetch('https://jsonplaceholder.typicode.com/posts/1').then(res => res.json()),
  fetch('https://jsonplaceholder.typicode.com/posts/2').then(res => res.json())
])
.then(([data1, data2]) => {
  console.log('Data 1:', data1);
  console.log('Data 2:', data2);
})
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

With fetch(), you use Promise.all() to handle multiple requests, requiring manual parsing for each response.

2. File Uploads & Progress Indicators

File uploads and showing progress are easier in Axios due to built-in support:

Axios Example (Progress Indicator for File Upload):

axios.post('/upload', formData, {
  onUploadProgress: progressEvent => {
    const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
    console.log(`Upload Progress: ${percentCompleted}%`);
  }
});
Enter fullscreen mode Exit fullscreen mode

Axios’ onUploadProgress callback is perfect for showing upload progress in real time.

fetch() Example (File Upload and Download Progress):

const formData = new FormData();
formData.append('file', file);

fetch('/upload', {
  method: 'POST',
  body: formData
})
.then(response => response.json())
.then(data => console.log('File uploaded successfully'))
.catch(error => console.error('Error:', error));

// Download Progress
fetch('https://example.com/large-file')
  .then(response => {
    const reader = response.body.getReader();
    let receivedLength = 0;
    const contentLength = response.headers.get('Content-Length');

    reader.read().then(function process({ done, value }) {
      if (done) {
        console.log('Download complete');
        return;
      }
      receivedLength += value.length;
      console.log(`Received ${receivedLength} of ${contentLength}`);
      return reader.read().then(process);
    });
  })
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

With fetch(), implementing file progress requires handling ReadableStream manually, which adds complexity.

Real-world Scenarios: When to Use Axios vs fetch()

Deciding between Axios vs fetch depends largely on the specific needs of your project. Here’s a look at when each tool is most effective:

1. Use Cases Where Each Shines

  • Small Projects: If you’re building a simple project that requires basic data fetching, fetch() is often the better choice. It’s lightweight, built into the browser, and avoids adding external dependencies. This makes it perfect for straightforward tasks like fetching JSON data from an API or submitting a form.

Example: A personal blog or a small website that only needs to make a few API requests can use fetch() without the overhead of a larger library.

  • Enterprise Applications: In large-scale projects, Axios offers distinct advantages. Its built-in features like interceptors, global configurations, and automatic data transformation simplify code maintenance and error handling. This makes Axios a better fit for complex applications where structured and consistent HTTP handling is crucial.

Example: A financial dashboard that interacts with multiple APIs and requires robust error handling would benefit from Axios’ streamlined setup and features.

2. Cost-Benefit Analysis

Choosing between Axios vs fetch often involves evaluating whether Axios’ benefits justify the additional dependency. For small projects, fetch() is often sufficient, minimizing bundle size and simplifying setup. However, in enterprise applications where maintainability, code consistency, and advanced features matter, Axios’ advantages can outweigh the cost of adding a library.

Handling CORS

1. What is CORS?

Cross-Origin Resource Sharing (CORS) is a security feature that allows servers to specify who can access their resources. When making requests to a different domain, a CORS policy ensures that your application is allowed to fetch data securely.

  • Axios and fetch() handle CORS requests similarly since they both rely on the browser’s CORS policies. A common mistake is adding Access-Control-Allow-Origin headers in the request—this header should only be set by the server. Properly configured servers will include this header in the response to indicate allowed origins.

2. Proper CORS Setup Examples

Axios Example:

axios.get('https://example.com/api', {
  headers: {
    'Content-Type': 'application/json'
  }
})
.catch(error => console.error('CORS Error:', error));
Enter fullscreen mode Exit fullscreen mode

fetch() Example:

fetch('https://example.com/api', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  }
})
.catch(error => console.error('CORS Error:', error));
Enter fullscreen mode Exit fullscreen mode

In both cases, make sure the server is configured to allow cross-origin requests.

Performance Optimization Tips

Optimizing both Axios and fetch() can help improve application performance, especially when handling large amounts of data or making frequent requests.

1. Caching

  • Axios: Use a caching library like axios-cache-adapter to cache responses and reduce redundant network requests.
  • fetch(): Implement a simple cache mechanism using the localStorage or sessionStorage APIs to store fetched data.

2. Response Handling

Efficiently handle responses to reduce network load:

  • Axios: Use interceptors to manage responses globally and only parse relevant data.
  • fetch(): Avoid fetching unnecessary data by using URL parameters or query strings to limit server responses.

3. Minimizing Network Load

  • Axios: Use the CancelToken feature to cancel requests if they are no longer needed, reducing wasted network load.
  • fetch(): Utilize AbortController to terminate unwanted requests.

By understanding when to use Axios vs fetch and applying these optimization techniques, you can ensure your project runs smoothly while minimizing network impact.

Conclusion

Choosing between Axios vs fetch ultimately depends on the complexity and requirements of your project. Axios is ideal for larger, enterprise-level applications where structured code, centralized error handling, and built-in features like interceptors can streamline development. On the other hand, fetch() is perfect for smaller projects that require simple, lightweight data fetching without the overhead of an additional library. For developers prioritizing quick implementation with minimal setup, Axios offers convenience, while those seeking full control and flexibility will appreciate fetch(). If you're considering alternatives, explore how React Query vs Axios compares to understand more advanced data-fetching strategies. Your choice should align with the scale and demands of your application, balancing simplicity, performance, and code maintainability.

Top comments (0)