/

Managing file uploads in forms using Express

Managing file uploads in forms using Express

Learn how to handle and store files uploaded via forms in Express.

This is an example of an HTML form that allows users to upload files:

1
2
3
4
<form method="POST" action="/submit-form" enctype="multipart/form-data">
<input type="file" name="document" />
<input type="submit" />
</form>

Don’t forget to include enctype="multipart/form-data" in the form, otherwise files won’t be uploaded.

When the user presses the submit button, the browser will send a POST request to the /submit-form URL on the same origin of the page. The data is sent as multipart/form-data instead of the normal form application/x-www-form-urlencoded encoding.

Handling multipart data on the server-side can be challenging and error-prone. To simplify this process, we will use a utility library called formidable. You can find the GitHub repository here, which has over 4000 stars and is well-maintained.

To install formidable, run the following command:

1
npm install formidable

Next, include the formidable module in your Node.js file:

1
2
3
const express = require('express');
const app = express();
const formidable = require('formidable');

Now, in the POST endpoint for the /submit-form route, create a new instance of Formidable using formidable.IncomingForm():

1
2
3
app.post('/submit-form', (req, res) => {
new formidable.IncomingForm();
});

After instantiating the Formidable form, we need to be able to parse the form data. We can do this synchronously by providing a callback function. This means that all files are processed, and once formidable has finished, they become available:

1
2
3
4
5
6
7
8
9
10
11
12
13
app.post('/submit-form', (req, res) => {
new formidable.IncomingForm().parse(req, (err, fields, files) => {
if (err) {
console.error('Error', err);
throw err;
}
console.log('Fields', fields);
console.log('Files', files);
for (const [name, file] of Object.entries(files)) {
console.log(name, file);
}
});
});

Alternatively, you can use events instead of a callback. For example, to be notified when each file is parsed or for other events such as file processing completion, receiving a non-file field, or encountering an error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
app.post('/submit-form', (req, res) => {
new formidable.IncomingForm().parse(req)
.on('field', (name, field) => {
console.log('Field', name, field);
})
.on('file', (name, file) => {
console.log('Uploaded file', name, file);
})
.on('aborted', () => {
console.error('Request aborted by the user');
})
.on('error', (err) => {
console.error('Error', err);
throw err;
})
.on('end', () => {
res.end();
});
});

Regardless of which approach you choose, you’ll receive one or more Formidable.File objects, which provide information about the uploaded file. Here are some of the methods you can use:

  • file.size: the file size in bytes
  • file.path: the path where the file is written to
  • file.name: the name of the file
  • file.type: the MIME type of the file

By default, the file is stored in the temporary folder. You can modify the file path by listening for the fileBegin event:

1
2
3
4
5
6
7
8
9
10
app.post('/submit-form', (req, res) => {
new formidable.IncomingForm().parse(req)
.on('fileBegin', (name, file) => {
file.path = __dirname + '/uploads/' + file.name;
})
.on('file', (name, file) => {
console.log('Uploaded file', name, file);
})
// ...
});

tags: [“Node.js”, “Express”, “file uploads”, “forms”, “file handling”, “formidable”]