Download Files as Blobs in the Browser with Axios

Downloading files directly in client-side applications often requires handling binary data efficiently. This guide outlines the complete process of using the Axios HTTP client to fetch binary data as a JavaScript Blob, generate a temporary object URL, and trigger a seamless file download in the user's browser.

1. Set the Response Type to blob

By default, Axios parses responses as JSON or plain text. When requesting a binary file (such as a PDF, CSV, or ZIP), you must explicitly set the responseType configuration property to 'blob'. This instructs Axios to preserve the raw binary data as a browser-compatible Blob object.

import axios from 'axios';

const downloadFile = async (url) => {
  try {
    const response = await axios.get(url, {
      responseType: 'blob', // Crucial for binary data
    });
    return response;
  } catch (error) {
    console.error('Download failed:', error);
  }
};

2. Generate a Temporary Object URL

Once Axios resolves the request, the response payload (response.data) contains the Blob instance. Use the native window.URL.createObjectURL() method to create a temporary URL representing the Blob data in the browser's memory.

const blob = new Blob([response.data], { type: response.headers['content-type'] });
const downloadUrl = window.URL.createObjectURL(blob);

3. Programmatically Trigger the Download

Browsers do not automatically prompt a "Save As" dialog when fetching data via JavaScript. To trigger the download action:

  1. Create a hidden HTML anchor (<a>) element.
  2. Assign the generated Blob URL to the href attribute.
  3. Specify the desired file name using the download attribute.
  4. Append the anchor to the document body, simulate a click, and remove it.
const link = document.createElement('a');
link.href = downloadUrl;
link.setAttribute('download', 'filename.pdf'); // Set the desired file name
document.body.appendChild(link);
link.click();
link.remove();

4. Revoke the Object URL

Object URLs remain in memory until the current document is unloaded or explicitly released. To prevent memory leaks, call window.URL.revokeObjectURL() after the download is initiated.

window.URL.revokeObjectURL(downloadUrl);

Complete Implementation Example

Below is a reusable function that handles the complete lifecycle from request to cleanup:

import axios from 'axios';

async function downloadBlobFile(fileUrl, defaultFilename = 'downloaded_file') {
  try {
    const response = await axios.get(fileUrl, {
      responseType: 'blob',
    });

    // Extract filename from Content-Disposition header if available
    let filename = defaultFilename;
    const contentDisposition = response.headers['content-disposition'];
    if (contentDisposition) {
      const filenameMatch = contentDisposition.match(/filename="?(.+)"?/i);
      if (filenameMatch && filenameMatch[1]) {
        filename = filenameMatch[1];
      }
    }

    // Create a Blob from the response data
    const blob = new Blob([response.data]);
    const downloadUrl = window.URL.createObjectURL(blob);

    // Create a temporary anchor to trigger the download
    const link = document.createElement('a');
    link.href = downloadUrl;
    link.download = filename;
    document.body.appendChild(link);
    link.click();

    // Clean up
    link.remove();
    window.URL.revokeObjectURL(downloadUrl);
  } catch (error) {
    console.error('An error occurred during file download:', error);
  }
}

Handling Error Responses with Blobs

If an API request fails (e.g., returning a 400 or 500 status with a JSON error body), Axios will still process the error response as a Blob due to the responseType: 'blob' setting. To read the server's error message, convert the error Blob back to text:

try {
  await axios.get('/api/download', { responseType: 'blob' });
} catch (error) {
  if (error.response && error.response.data instanceof Blob) {
    const errorText = await error.response.data.text();
    const errorJson = JSON.parse(errorText);
    console.error('Server error details:', errorJson);
  }
}