What's the correct way to send files using JavaScript fetch method?

I’m having trouble figuring out how to properly send files to a server using the fetch API in JavaScript.

I have a basic HTML form that lets users pick files:

<form id="fileForm">
  <div>
    <span>Choose your file</span>
    <input type="file" id="fileInput">
  </div>
  <button type="submit">Upload</button>
</form>

I can capture the form submission event without any issues. However, I’m stuck on how to actually pass the selected file to the fetch request. Here’s what I have so far:

fetch('/upload-endpoint', {
  method: 'POST',
  // I'm not sure what should go in the body here
  // Do I need special headers for file uploads?
}).then(response => {
  // handle response
});

What’s the proper way to structure the request body and headers when uploading files with fetch?

Had the same headaches with file uploads until I figured out the multiple file handling part that others missed. When you’re dealing with multiple files from your input (just throw multiple on your file input), you’ve got to loop through the FileList: javascript const files = document.getElementById('fileInput').files; const formData = new FormData(); for (let i = 0; i < files.length; i++) { formData.append('files[]', files[i]); } One thing that bit me was file name encoding with special characters. Browsers handle most stuff fine but I’ve hit issues with certain Unicode characters in filenames. Older browsers also have size limits on FormData objects. For better UX, check files.length before processing and maybe show the selected filenames so users know what they’re uploading. Makes debugging way easier when the server-side breaks.

u need FormData for this. get the file using document.getElementById('fileInput').files[0], then create a FormData instance: const formData = new FormData(); formData.append('file', yourFile);. put formData in the body and skip the content-type header - browser manages that.

FormData is definitely the way to go here. I’ve dealt with this exact scenario tons of times.

Here’s what your complete code should look like:

const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];

if (file) {
  const formData = new FormData();
  formData.append('file', file);
  
  fetch('/upload-endpoint', {
    method: 'POST',
    body: formData
  })
  .then(response => response.json())
  .then(data => console.log(data));
}

Don’t set Content-Type header manually - the browser handles multipart/form-data automatically with FormData.

Need to send extra data with the file? Just append more fields:

formData.append('userId', '123');
formData.append('description', 'My uploaded file');

I always add file size validation before upload. Saves server resources and gives users better feedback.

FormData works but gets messy with complex upload workflows.

Hit this exact problem building file uploads for our platform. Started with basic FormData but quickly ran into issues when users needed progress tracking, retry logic, or cloud storage integration.

Game changer was setting up automated workflows for the entire upload pipeline. Instead of writing custom JavaScript for every scenario, I built flows handling file validation, progress updates, error handling, and automatic resizing or format conversion.

Your frontend just triggers the workflow and gets status updates. No more FormData quirks, timeout issues, or manual error handling. The automation handles chunked uploads for large files, validates server-side, and connects directly to your storage service.

Used this for everything from profile pictures to complex document processing. Way cleaner than maintaining custom fetch code for each case.

Check out how you can automate your entire file upload flow: https://latenode.com