I am Hack Sparrow
Captain of the Internets.

Handle File Uploads in Express (Node.js)

How to handle file uploads in Express Node.js framework

Handling file uploads was a pain in Node.js some time ago. Then came formidable. It was a good start but uploading files was still not easy. Then came connect-form which made things a little easier, based on which I wrote a tutorial on handling POST requests in Express.

In the rapidly progressing Node.js landscape, it wasn't going to be long before the crucial file uploading functionality would become actually very easy. The time has come now - handling file uploads in very easy now in Express.

You no more require any extra module to work with file uploads in Express. File upload now works right out of the Express box. Along with req.body, now you have req.files which contains the details about the files you have uploaded.

If you don't want to specify the upload directory, you are all set to start processing file uploads without any additional changes to app.js. The files are uploaded to "/tmp" by default. If you want to make sure the files are uploaded to a specific directory, you change this

app.use(express.bodyParser());

to

app.use(express.bodyParser({uploadDir:'./uploads'}));

The express.bodyParser config option can found on line 16 as of Express v2.5.4. In the above example, the files will be uploaded to a directory named "uploads" in the same dir as the Express app.

To get a better idea about how the file upload and POST submission can be handled, let's create a form:

<form method="post" enctype="multipart/form-data" action="/file-upload">
<input type="text" name="username">
<input type="password" name="password">
<input type="file" name="thumbnail">
<input type="submit">
</form>

To handle the form submission, let's create a route:

app.post('/file-upload', function(req, res, next) {
console.log(req.body);
console.log(req.files);
});

It's that simple now!

In the above example, we can access the file from the req.files.thumbnail object. The object name is dependent what you set the name attribute to in your HTML form. In our case we set it as "thumbnail", so we access it from req.files.thumbnail.

A file object has these commonly useful properties:

size - size of the file in bytes
path - the uploaded location of the file (files are renamed after uploading)
name - original name of the file (as on your hard disk)
type - the type of the file

To know the size of the file in our case: req.files.thumbnail.size
To know the original name of the file in our case: req.files.thumbnail.name
etc.

Note that the "uploads" directory is just the temporary upload directory; you will need to move the files to their respective intended locations once they are uploaded there. Following is an example of doing that. In this case we will be uploading the files to the "images" directory.

// we need the fs module for moving the uploaded files
var fs = require('fs');
app.post('/file-upload', function(req, res) {
    // get the temporary location of the file
    var tmp_path = req.files.thumbnail.path;
    // set where the file should actually exists - in this case it is in the "images" directory
    var target_path = './public/images/' + req.files.thumbnail.name;
    // move the file from the temporary location to the intended location
    fs.rename(tmp_path, target_path, function(err) {
        if (err) throw err;
        // delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files
        fs.unlink(tmp_path, function() {
            if (err) throw err;
            res.send('File uploaded to: ' + target_path + ' - ' + req.files.thumbnail.size + ' bytes');
        });
    });
};

You can set the upload destination to anywhere in the OS where you have access to. In case you want the files to be publicly available they should be uploaded within the "public" directory of Express. If want to upload the files to any sub-directory with "public", make sure they already exist else you will run into "Error: ENOENT, no such file" or directory error.

That's it! Handling file uploads in very easy in Express now. In case your old app is not handling file uploads as expected, try updating to the latest version of Express and NPM, and re-create the app. Any queries, suggestions; ping me in the comments.

49 Responses to “Handle File Uploads in Express (Node.js)”

  1. Captain says:

    Make sure, you gave specified the enctype: form(action=’/signup’, method=’post’, enctype=’multipart/form-data’)

  2. ALi says:

    console.log(req.body);
    console.log(req.files);

    these two lines give me undefined..

    bodyParser(); is replace by

    app.use(express.urlencoded());
    app.use(express.json());

    how to use this replace thing???

  3. Jon Jenkins says:

    I created an example that uses Express & Multer – very simple, avoids all Connect warnings

    https://github.com/jonjenkins/express-upload

    Might help somebody.

  4. Chris says:

    I was following this example but I get an internal server error when uploading a file.
    All I get in the console is Error: Forbidden. Has anyone ever encountered this before?

  5. Shown says:

    @Captain ,

    I’ve read all the comments before, and found that even the article is very clear, still a few guys cannot get the right result. such as @ALi , @aMartini , @zz , @ryan and me.

    I checked numbers of times that the code is same as that in the article, but the result of
    console.log(req.body);
    console.log(req.files);
    is:
    {}
    undefined

    if I remove the
    enctype=”multipart/form-data”
    of the form,
    console.log(req.body);
    console.log(req.files);
    is
    { username: ‘s’, password: ’1′, thumbnail: ‘w.txt’ }
    undefined

    what I’m using is
    Windows OS nodejs 0.10.24
    express 3.4.8
    and have tried express 3.5.4
    and ejs module

    Do you think that’s the problem of the version?
    Do you think that’s the problem of the unicode?(I’m using UTF-8)
    Do you think there’re still some error in the code?

    Thank you very much for you help!

  6. Shown says:

    Sorry, I found the reason:

    app.use(express.bodyParser({uploadDir:’./tmp’}));
    //Must be put before app.use(app.router);
    app.use(app.router);

  7. charef says:

    Hi,
    i have the same probleme even that i puted the app.use(express.bodyParser({uploadDir:’./tmp’}));
    before app.use(app.router);

    someone can help me please !!

  8. Jer Thorp says:

    For anyone who is struggling with this, I found that the encoding (enctype=’multipart/form-data’) couldn’t be handled without installing the multer package (npm install multer)

  9. donny says:

    when printed req.files.thumbnail.path i got this :uploads\7ebfd0a3010a7be0822221507fe196b0.
    how to acess 7ebfd0a3010a7be0822221507fe196b0 column.

    someone can help me please

Make a Comment