File APIs: File upload with server handling

Join the AI Workshop to learn more about AI and how it can be applied to web development. Next cohort February 1st, 2026

The AI-first Web Development BOOTCAMP cohort starts February 24th, 2026. 10 weeks of intensive training and hands-on projects.


When you upload a file from the browser, you need both client-side and server-side code to handle it.

Client-side upload

Given a file input element:

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

We register a change handler and use FormData to send the file:

const handleImageUpload = event => {
  const files = event.target.files
  const formData = new FormData()
  formData.append('myFile', files[0])

  fetch('/saveImage', {
    method: 'POST',
    body: formData
  })
  .then(response => response.json())
  .then(data => {
    console.log(data.path)
  })
  .catch(error => {
    console.error(error)
  })
}

document.querySelector('#fileUpload').addEventListener('change', event => {
  handleImageUpload(event)
})

Validating files before upload

You can check the file type or size before sending:

const handleImageUpload = event => {
  const files = event.target.files
  const myImage = files[0]
  const imageType = /image.*/

  if (!myImage.type.match(imageType)) {
    alert('Sorry, only images are allowed')
    return
  }

  if (myImage.size > (100*1024)) {
    alert('Sorry, the max allowed size for images is 100KB')
    return
  }

  //...proceed with upload
}

Server-side handling with Node.js

Using Node.js with Express, install the express-fileupload module:

npm install express-fileupload

Add it to your middleware:

import fileupload from 'express-fileupload'

app.use(fileupload())

This is required for the server to parse file uploads. Without it, req.files would be undefined.

Handle the upload in your route:

app.post('/saveImage', (req, res) => {
  const fileName = req.files.myFile.name
  const path = __dirname + '/uploads/' + fileName

  req.files.myFile.mv(path, (error) => {
    if (error) {
      console.error(error)
      res.writeHead(500, {
        'Content-Type': 'application/json'
      })
      res.end(JSON.stringify({ status: 'error', message: error }))
      return
    }

    res.writeHead(200, {
      'Content-Type': 'application/json'
    })
    res.end(JSON.stringify({ status: 'success', path: '/uploads/' + fileName }))
  })
})

The mv method is provided by express-fileupload to move the uploaded file to its destination.

Server-side handling with Astro

With Astro, you can access uploaded files using:

const formData = await Astro.request.formData()
console.log(formData.getAll('files'))

Lessons in this unit:

0: Introduction
1: The File object
2: FileList
3: FileReader
4: Blob
5: FormData
6: Accept only images in file input
7: Check if checkbox is checked
8: Reset a form
9: ▶︎ File upload with server handling
10: Drag and drop file upload
11: Validating file size before upload