How to Send multipart/form-data Using Axios

This guide explains how to properly send multipart/form-data payloads, such as files and binary data, using the Axios HTTP client. You will learn the correct implementation methods for both browser and Node.js environments, how modern Axios handles boundary headers automatically, and common pitfalls to avoid during implementation.

Sending Form Data in the Browser

In modern browsers, the standard approach relies on the native FormData interface.

import axios from 'axios';

const uploadFile = async (file, textDescription) => {
  const formData = new FormData();
  formData.append('file', file);
  formData.append('description', textDescription);

  try {
    const response = await axios.post('https://api.example.com/upload', formData);
    console.log('Upload successful:', response.data);
  } catch (error) {
    console.error('Upload failed:', error);
  }
};

Automatic Content-Type Management

Do not manually set the Content-Type header to multipart/form-data. When left unset, Axios and the browser automatically assign the header along with the required unique boundary string (e.g., multipart/form-data; boundary=----WebKitFormBoundary...). Manually setting this header without the boundary will cause the server to fail to parse the incoming payload.


Automatic Serialization (Axios v1.x+)

Modern versions of Axios support automatic serialization. You can pass a standard JavaScript object containing file references or Blob instances, and specify multipart/form-data in the request configuration.

import axios from 'axios';

const uploadDirectly = async (fileInput) => {
  try {
    const response = await axios.post(
      'https://api.example.com/upload',
      {
        file: fileInput.files[0],
        fileName: 'example.png',
      },
      {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      }
    );
    console.log(response.data);
  } catch (error) {
    console.error(error);
  }
};

Sending Form Data in Node.js

In Node.js environments prior to native FormData support (Node.js 18+), you must use the form-data package or read streams.

Using Node.js Streams with form-data

const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

async function uploadFileNode() {
  const form = new FormData();
  form.append('file', fs.createReadStream('/path/to/file.pdf'));
  form.append('user', 'John Doe');

  try {
    const response = await axios.post('https://api.example.com/upload', form, {
      headers: {
        ...form.getHeaders(),
      },
    });
    console.log('File uploaded:', response.data);
  } catch (error) {
    console.error('Error uploading file:', error);
  }
}

When using the form-data library in Node.js, calling form.getHeaders() is required to supply the correct boundary metadata generated by the library.


Tracking Upload Progress

Axios provides the onUploadProgress callback, which allows you to monitor the transmission state for large payloads:

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