How to upload a file with fetch
Short answer
Take the file from an input field, put it into FormData and send it as the body:
<input type="file" id="avatar">
<script>
document.getElementById('avatar').addEventListener('change', async (event) => {
const file = event.target.files[0];
const data = new FormData();
data.append('avatar', file);
const response = await fetch('/api/avatar', { method: 'POST', body: data });
console.log(response.status);
});
</script>Several files and fields
Add each file under the same name, and ordinary fields next to them:
const data = new FormData();
for (const file of input.files) {
data.append('photos', file);
}
data.append('album', 'Summer 2025');
await fetch('/api/photos', { method: 'POST', body: data });Checking before upload
Check the size and type in the browser to save the user time. The server must still check them again:
const maxSize = 2 * 1024 * 1024;
const allowed = ['image/png', 'image/jpeg'];
if (!allowed.includes(file.type)) {
showMessage('Only PNG and JPEG images');
} else if (file.size > maxSize) {
showMessage('The file is larger than 2 MB');
}Common mistake
Do not set the Content-Type header yourself when sending FormData. The browser adds it with a special boundary string, and without it the server cannot read the file:
// wrong
await fetch('/api/avatar', {
method: 'POST',
headers: { 'Content-Type': 'multipart/form-data' },
body: data,
});Functions used in this recipe
- fetch — Sends an HTTP request and returns a promise of the response.