Skip to content

Send a File With Axios in Node.js

5 min read

Programatically sending requests in Node.js can be a frustrating experience. First, you have to choose one out of many request libraries in the ecosystem. Second, they each have a slightly different API which is confusing when you're switching.

You also have to make sure the request is formatted in a specific way for the 3rd party on the receiving end to accept it.

Just as you're starting to get the hand of axios, you soon find out there are (subtle) usage differences depending on whether you're in the browser or Node.js.

What a pain.

Only if uploading files with axios in Node.js would be as easy as taking a walk in the park.

Well, it can be.

In this article, you'll learn how to send files and associated data by constructing a form. We'll cover the two file types — Buffers and Streams, and how to work with them.

Construct a form with form-data library

Before uploading a file with axios, you first need to create a form and append the file to it. Axios can be used both in the frontend as backend and the library doesn't differentiate between the two. Therefore, sending a file with axios in Node.js is similar to sending a file with axios in the browser.

Because we don't have access to the FormData interface in Node.js as we do in the browser, we use the form-data library to construct a form. This is similar to a <form> element with encoding type set to "multipart/form-data" in the browser.

To construct a form, create a new FormData instance and use the append(name, value) method to add a file and additional fields.

// `form-data` library gives us a similar API in Node.js to the `FormData` interface in the browser
const FormData = require('form-data');

// Create a new form instance
const form = new FormData();

// Append text fields to the form
form.append('productName', 'Node.js Stickers');
form.append('productDescription', 'Cool collection of Node.js stickers for your laptop.');

// `file` can either be a Buffer or a Stream
// ⚠️ don't forget the 3rd argument, the file name, when appending a file
form.append('productImage', file, 'stickers.jpg');

Notice that when adding a file to the form, the append function takes three arguments instead of two. The third argument is the file name and if it's missing, the file won't send properly so make sure to pass it along.

The second argument is the file itself, which can either be a Buffer or a Stream. Let's look at a few real examples of how and why you would use either two.

File as a Buffer

A file buffer (or blob) is what you'll encounter most often when dealing with files. It's essentially the entire file stored in binary format in the application's memory.

If you're familiar with multer, it uses MemoryStorage by default which is essentially storing the files in memory as a Buffer. Reading a file from disk with fs.readFile() also gives you the file stored as a Buffer.

In both cases, you can append the file buffer to the FormData form:

const form = new FormData();

// File parsed by multer from incoming request
const file = req.file;
form.append('file', file.buffer, file.originalname);

// or read from disk
const file = await fs.readFile('./my-image.jpg');
form.append('file', file, 'my-image.jpg');

File as a Stream

You can also append a file as a stream to the form. This is useful when, for example, the file is fetched from an external resource. You can then proxy the file directly to another API without storing it locally.

// Fetch external image as a stream
const response = await axios.get('https://i.imgur.com/8uJcFxW.jpg', { responseType: 'stream' });

const form = new FormData();
// Pass image stream from response directly to form
form.append('image', response.data, 'kitten.jpg');

Another good example is when you're dealing with large files. Using streams instead of buffer could prevent your application from consuming too much memory and eventually crashing.

// Open file as a readable stream
const fileStream = fs.createReadStream('./large-file.zip');

const form = new FormData();
// Pass file stream directly to form
form.append('largeFile', fileStream, 'large-file.zip');

To upload multiple files, you simply append them one by one to the form.

Send the form with axios

Now let's send the FormData form with axios. The axios API for sending a POST request is:

axios.post(url[, data[, config]]), where:

  • url - server URL that will be used for the request
  • data (optional) - the data to be sent as the request body
  • config (optional) - configuration object where you can set the request headers, amongst others

To send a form with axios in Node.js, you have to grab the form boundary and add it to the request.

The getHeaders() method on the form returns an object with Content-Type header set to multipart/form-data plus a unique boundary:

// form.getHeaders() gives you the Content-Type header with a unique boundary
console.log(form.getHeaders());
// {
//   'content-type': 'multipart/form-data; boundary=--------------------------339261229255605205279691'
// }

Use the destructuring assignment to set the Content-Type header in the config parameter (3rd argument). This allows you to add additional headers if you wish to do so.

Here's how to send a form with axios:

// When using axios in Node.js, you need to set the Content-Type header with the form boundary
// by using the form's `getHeaders()` method
const response = await axios.post(url, form, {
  headers: {
    ...form.getHeaders(),
    Authorization: 'Bearer ...', // optional
  },
});

Everything put together

To summarise, uploading a file with axios in Node.js requires you to do two important things:

  1. Create a form with the form-data library
  2. Grab the Content-Type header with the form's boundary with form.getHeaders() and assign it to the axios request

We've looked at different ways to append a file to a form, either as a Buffer or a Stream. Below is a complete example that reads a file from disk into a Buffer and uploads it to an external API with axios.

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

// Read image from disk as a Buffer
const image = await fs.readFile('./stickers.jpg');

// Create a form and append image with additional fields
const form = new FormData();
form.append('productName', 'Node.js Stickers');
form.append('productDescription', 'Cool collection of Node.js stickers for your laptop.');
form.append('productImage', image, 'stickers.jpg');

// Send form data with axios
const response = await axios.post('https://example.com', form, {
  headers: {
    ...form.getHeaders(),
    Authentication: 'Bearer ...',
  },
});

How do you upload a file in Node.js?

Use this FREE request parsing guide and implement seamless working Node.js APIs that follow the latest best practices.

5 thumbnail images of the pages inside the Request Parsing in Node.js Guide. It covers frontend and backend examples of the most common Content-Type requests.

You'll also get tips on building scalable Node.js applications about twice a month. I respect your email privacy. Unsubscribe any time.

You might also like

Fix "Unexpected field" Error From Multer

Learn how to decypher & fix this cryptic error message from multer, and finally implement working file uploads in Node.js.
Read article

Why Storing Files in the Database Is Considered Bad Practice

Everyone says you shouldn't store files in the database, but why? Find out why and learn a better approach to file storage.
Read article

From PM2 to Docker: Automatic Restarts

Migrating from PM2 to Docker? Curious if Docker can live up to PM2? Let's compare automatic restarts between the two tools.
Read article