How to upload a file using the Fetch API

Reading Time: 3 minutes 🕑

Last updated: August 24, 2022.

When using Fetch API to upload a file (or files) to a server, you have two options: to store the file in a formData object or as a standalone file.

In case you are unfamiliar with making POST or PUT requests with the Fetch API, you may want to review our guide to using Fetch before proceeding with this tutorial.

Table of contents

Uploading a file stored in a FormData object

This is the most common way to upload a file using Fetch.

First, you need to create a form with an <input> element of type file. Make sure a <button> element of type submit is also included:

<form id="form">
    <input type="file" id="file"></input>
    <button type="submit">Upload file</button>
</form>

Now, you can handle the submission of the form using the code below.

Note how the file is appended to a FormData object before it is posted using Fetch. The append format is payload.append('key', payload, 'filename.ext'). The third argument is optional.

By appending to a FormData object, the payload is sent as it would be in a HTML form in which the encoding type is set to multipart/form-data. This means no content-type property has to be set in the configuration object passed into Fetch. It will be set automatically.

/* Sending a file appended to a FormData object */

const form = document.getElementById('form');

form.addEventListener('submit', function(event) {
  // Prevent default HTML page refresh
  event.preventDefault();

  // Select file upload element
  const uploadElement = document.getElementById('file');

  // Extract the file (for a single file, always 0 in the list)
  const file = uploadElement.files[0];

  // Create new formData object then append file
  const payload = new FormData();
  payload.append('CV', file, 'CV.pdf');

  // POST/PUT with Fetch API
  fetch('https://httpbin.org/post', {
    method: "POST", // or "PUT"
    body: payload,
    // No content-type! With FormData obect, Fetch API sets this automatically.
    // Doing so manually can lead to an error
  })
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.log(err))
});

Sending as part of a larger form

If your form has other input, you need to append it to the FormData object as well.

For example:

/* Appending file and user input to the payload */

const payload = new FormData();
payload.append('CV', file, 'CV.pdf');
payload.append('First name', document.getElementById('firstName').value);
payload.append('Last name', document.getElementById('lastName').value);

Viewing the contents of a FormData object

As the FormData object is a special type, you cannot view is contents by logging it to the console.

Data is stored in key-values pairs. So you can view the contents by iterating through it with a loop and logging each key and value to the console:

/* Extracting data from a FormData object */

for (let item of payload.entries()) {
  console.log(item[0]+ ', ' + item[1]); 
}

Allowing multiple files for single input

To allow the user send multiple files in one upload, add the multiple attribute to an <input> element in your HTML.

Note that when using this method, the user must select multiple files when browsing their system.

For example:

<input type="file" id="file" multiple></input>

Then, inside the function that submits the form, insert a check for the length of the files selected by the user. If the length is greater than your maximum, return a value to stop the function executing and prevent form submission:

/* A check on the number of files */

if (uploadElement.files.length) {
  alert("You can only upload a maximum of 2 files");
  return false;
}

Uploading a file without appending to FormData

Appending to a FormData object is standard practice, but you don’t need to do so.

Without using a form at all, your HTML can be as simple as this:

<input type="file" id="file"></input>
<button id="submit">Upload file</button>

The disadvantage is that you then have to set the Content-Type header manually:

/* Uploading a file without appending to FormData */

const btn = document.getElementById('submit');

btn .addEventListener('click', function(event) {
  const uploadElement = document.getElementById('file');
  const payload = uploadElement.files[0];

  // POST with Fetch
  fetch('https://httpbin.org/post', {
    method: "POST",
    body: payload,
    headers: {
      'Content-Type': "image/png"
    },
  })
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.log(err))
});

Related links