[node.js] Uploading images using Node.js, Express, and Mongoose

Please consider newer answers that have more up-to-date information as things have changed over the years!

Since many new Node.js libraries are quickly being rendered obsolete and there are relatively few examples anyways I want to ask about uploading images using:

  • Node.js (v0.4.1)
  • Express (1.0.7)
  • Mongoose (1.1.0).

How have others done it?

I've found: node-formidable, but I am new to uploading images in general so I want to learn general stuff and ways of doing so using Node.js and Express.

This question is related to node.js image file-upload express mongoose

The answer is


I created an example that uses Express and Multer. It is very simple and avoids all Connect warnings

It might help somebody.


There's my method to multiple upload file:

Nodejs :

router.post('/upload', function(req , res) {

var multiparty = require('multiparty');
var form = new multiparty.Form();
var fs = require('fs');

form.parse(req, function(err, fields, files) {  
    var imgArray = files.imatges;


    for (var i = 0; i < imgArray.length; i++) {
        var newPath = './public/uploads/'+fields.imgName+'/';
        var singleImg = imgArray[i];
        newPath+= singleImg.originalFilename;
        readAndWriteFile(singleImg, newPath);           
    }
    res.send("File uploaded to: " + newPath);

});

function readAndWriteFile(singleImg, newPath) {

        fs.readFile(singleImg.path , function(err,data) {
            fs.writeFile(newPath,data, function(err) {
                if (err) console.log('ERRRRRR!! :'+err);
                console.log('Fitxer: '+singleImg.originalFilename +' - '+ newPath);
            })
        })
}
})

Make sure your form has enctype="multipart/form-data"

I hope this gives you a hand ;)


I'll answer my own question for the first time. I found an example straight from the source. Please forgive the poor indentation. I wasn't sure how to indent properly when copying and pasting. The code comes straight from Express multipart/form-data example on GitHub.

// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');

/**
 * Module dependencies.
 */

var express = require('../../lib/express')
  , form = require('connect-form');

var app = express.createServer(
  // connect-form (http://github.com/visionmedia/connect-form)
  // middleware uses the formidable middleware to parse urlencoded
  // and multipart form data
  form({ keepExtensions: true })
);

app.get('/', function(req, res){
  res.send('<form method="post" enctype="multipart/form-data">'
    + '<p>Image: <input type="file" name="image" /></p>'
    + '<p><input type="submit" value="Upload" /></p>'
    + '</form>');
});

app.post('/', function(req, res, next){

  // connect-form adds the req.form object
  // we can (optionally) define onComplete, passing
  // the exception (if any) fields parsed, and files parsed
  req.form.complete(function(err, fields, files){
    if (err) {
      next(err);
    } else {
      console.log('\nuploaded %s to %s'
        ,  files.image.filename
        , files.image.path);
      res.redirect('back');
    }
  });

  // We can add listeners for several form
  // events such as "progress"
  req.form.on('progress', function(bytesReceived, bytesExpected){
    var percent = (bytesReceived / bytesExpected * 100) | 0;
    process.stdout.write('Uploading: %' + percent + '\r');
  });
});

app.listen(3000);
console.log('Express app started on port 3000');

It will become easy to store files after converting in string you just have to convert string in image in your frontend

convert image in to base64 string using this code in your api and also don't forgot to delete file from upload folder

"img": new Buffer.from(fs.readFileSync(req.file.path)).toString("base64")

to delete the file

       let resultHandler = function (err) {
            if (err) {
                console.log("unlink failed", err);
            } else {
                console.log("file deleted");
            }
        }

        fs.unlink(req.file.path, resultHandler);

at your routes import multer

 `multer const multer = require('multer');
  const upload = multer({ dest: __dirname + '/uploads/images' });`
  Add upload.single('img') in your request

  router.post('/fellows-details', authorize([Role.ADMIN, Role.USER]), 
        upload.single('img'), usersController.fellowsdetails);

OR

If you want save images in localstorage and want save path in database you can try following approach

you have to install first the fs-extra which will create folder. I am creating separate folders by id's if you want to remove it you can remove it. and to save path of image where it is uploaded add this code in your api or controller you are using to save image and and add it in database with other data

    let Id = req.body.id;
    let path = `tmp/daily_gasoline_report/${Id}`;

create separate folder for multer like multerHelper.js

 const multer = require('multer');
 let fs = require('fs-extra');

 let storage = multer.diskStorage({
 destination: function (req, file, cb) {
    let Id = req.body.id;
    let path = `tmp/daily_gasoline_report/${Id}`;
    fs.mkdirsSync(path);
    cb(null, path);
 },
 filename: function (req, file, cb) {
    // console.log(file);

  let extArray = file.mimetype.split("/");
  let extension = extArray[extArray.length - 1];
  cb(null, file.fieldname + '-' + Date.now() + "." + extension);
 }
})

let upload = multer({ storage: storage });

let createUserImage = upload.array('images', 100);

let multerHelper = {
     createUserImage,
}

   module.exports = multerHelper;

In your routes import multerhelper file

   const multerHelper = require("../helpers/multer_helper");

   router.post(multerHelper. createUserImage , function(req, res, next) {
      //Here accessing the body datas.
    })

You can also use the following to set a path where it saves the file.

req.form.uploadDir = "<path>";

See, the best thing you can do is to just upload the image to the disk and save the URL in MongoDB. Rest when you retrieve the image again. Just specify the URL, and you will get an image. The code for uploading is as follows.

app.post('/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.
    target_path = '/tmp/' + 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;
            //
        });
    });
});

Now save the target path in your MongoDB database.

Again, while retrieving the image, just extract the URL from the MongoDB database, and use it on this method.

fs.readFile(target_path, "binary", function(error, file) {
    if(error) {
        res.writeHead(500, {"Content-Type": "text/plain"});
        res.write(error + "\n");
        res.end();
    }
    else {
        res.writeHead(200, {"Content-Type": "image/png"});
        res.write(file, "binary");
    }
});

Here's a way to upload your images using the formidable package, which is recommended over bodyParser in later versions of Express. This also includes the ability to resize your images on the fly:

From my website: Uploading and Resizing Images (on the fly) With Node.js and Express.

Here's the gist:

var express = require("express"),
app = express(),
formidable = require('formidable'),
util = require('util')
fs   = require('fs-extra'),
qt   = require('quickthumb');

// Use quickthumb
app.use(qt.static(__dirname + '/'));

app.post('/upload', function (req, res){
  var form = new formidable.IncomingForm();
  form.parse(req, function(err, fields, files) {
    res.writeHead(200, {'content-type': 'text/plain'});
    res.write('received upload:\n\n');
    res.end(util.inspect({fields: fields, files: files}));
  });

  form.on('end', function(fields, files) {
    /* Temporary location of our uploaded file */
    var temp_path = this.openedFiles[0].path;
    /* The file name of the uploaded file */
    var file_name = this.openedFiles[0].name;
    /* Location where we want to copy the uploaded file */
    var new_location = 'uploads/';

    fs.copy(temp_path, new_location + file_name, function(err) {  
      if (err) {
        console.error(err);
      } else {
        console.log("success!")
      }
    });
  });
});

// Show the upload form 
app.get('/', function (req, res){
  res.writeHead(200, {'Content-Type': 'text/html' });
  /* Display the file upload form. */
  form = '<form action="/upload" enctype="multipart/form-data" method="post">'+ '<input name="title" type="text" />
  '+ '<input multiple="multiple" name="upload" type="file" />
  '+ '<input type="submit" value="Upload" />'+ '</form>';
  res.end(form); 
}); 
app.listen(8080);

NOTE: This requires Image Magick for the quick thumb resizing.


Since you're using express, just add bodyParser:

app.use(express.bodyParser());

then your route automatically has access to the uploaded file(s) in req.files:

app.post('/todo/create', function (req, res) {
    // TODO: move and rename the file using req.files.path & .name)
    res.send(console.dir(req.files));  // DEBUG: display available fields
});

If you name the input control "todo" like this (in Jade):

form(action="/todo/create", method="POST", enctype="multipart/form-data")
    input(type='file', name='todo')
    button(type='submit') New

Then the uploaded file is ready by the time you get the path and original filename in 'files.todo':

  • req.files.todo.path, and
  • req.files.todo.name

other useful req.files properties:

  • size (in bytes)
  • type (e.g., 'image/png')
  • lastModifiedate
  • _writeStream.encoding (e.g, 'binary')

I know that the original question related to specific versions, but it also referred to the "latest" - @JohnAllen 's post is no longer relevant due to Expressjs bodyParser and connect-form

This demonstrates the easy to use in-built bodyParser():

 /**
 * Module dependencies.
 */

var express = require('express')

var app = express()
app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/home/svn/rest-api/uploaded' }))

app.get('/', function(req, res){
  res.send('<form method="post" enctype="multipart/form-data">'
    + '<p>Image: <input type="file" name="image" /></p>'
    + '<p><input type="submit" value="Upload" /></p>'
    + '</form>');
});

app.post('/', function(req, res, next){

    res.send('Uploaded: ' + req.files.image.name)
    return next()

});

app.listen(3000);
console.log('Express app started on port 3000');

For Express 3.0, if you want to use the formidable events, you must remove the multipart middleware, so you can create the new instance of it.

To do this:

app.use(express.bodyParser());

Can be written as:

app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart()); // Remove this line

And now create the form object:

exports.upload = function(req, res) {
    var form = new formidable.IncomingForm;
    form.keepExtensions = true;
    form.uploadDir = 'tmp/';

    form.parse(req, function(err, fields, files){
        if (err) return res.end('You found error');
        // Do something with files.image etc
        console.log(files.image);
    });

    form.on('progress', function(bytesReceived, bytesExpected) {
        console.log(bytesReceived + ' ' + bytesExpected);
    });

    form.on('error', function(err) {
        res.writeHead(400, {'content-type': 'text/plain'}); // 400: Bad Request
        res.end('error:\n\n'+util.inspect(err));
    });
    res.end('Done');
    return;
};

I have also posted this on my blog, Getting formidable form object in Express 3.0 on upload.


Again if you don't want to use bodyParser, the following works:

var express = require('express');
var http = require('http');
var app = express();

app.use(express.static('./public'));


app.configure(function(){
    app.use(express.methodOverride());
    app.use(express.multipart({
        uploadDir: './uploads',
        keepExtensions: true
    }));
});


app.use(app.router);

app.get('/upload', function(req, res){
    // Render page with upload form
    res.render('upload');
});

app.post('/upload', function(req, res){
    // Returns json of uploaded file
    res.json(req.files);
});

http.createServer(app).listen(3000, function() {
    console.log('App started');
});

Try this code.It will help.

app.get('/photos/new', function(req, res){
  res.send('<form method="post" enctype="multipart/form-data">'
    + '<p>Data: <input type="filename" name="filename" /></p>'
    + '<p>file: <input type="file" name="file" /></p>'
    + '<p><input type="submit" value="Upload" /></p>'
    + '</form>');
});


 app.post('/photos/new', function(req, res) {
  req.form.complete(function(err, fields, files) {
    if(err) {
      next(err);
    } else {
      ins = fs.createReadStream(files.photo.path);
      ous = fs.createWriteStream(__dirname + '/directory were u want to store image/' + files.photo.filename);
      util.pump(ins, ous, function(err) {
        if(err) {
          next(err);
        } else {
          res.redirect('/photos');
        }
      });
      //console.log('\nUploaded %s to %s', files.photo.filename, files.photo.path);
      //res.send('Uploaded ' + files.photo.filename + ' to ' + files.photo.path);
    }
  });
});

if (!module.parent) {
  app.listen(8000);
  console.log("Express server listening on port %d, log on to http://127.0.0.1:8000", app.address().port);
}

You can configure the connect body parser middleware in a configuration block in your main application file:

    /** Form Handling */
    app.use(express.bodyParser({
        uploadDir: '/tmp/uploads',
        keepExtensions: true
    }))
    app.use(express.limit('5mb'));

Examples related to node.js

Hide Signs that Meteor.js was Used Querying date field in MongoDB with Mongoose SyntaxError: Cannot use import statement outside a module Server Discovery And Monitoring engine is deprecated How to fix ReferenceError: primordials is not defined in node UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib error running php after installing node with brew on Mac internal/modules/cjs/loader.js:582 throw err DeprecationWarning: Buffer() is deprecated due to security and usability issues when I move my script to another server Please run `npm cache clean`

Examples related to image

Reading images in python Numpy Resize/Rescale Image Convert np.array of type float64 to type uint8 scaling values Extract a page from a pdf as a jpeg How do I stretch an image to fit the whole background (100% height x 100% width) in Flutter? Angular 4 img src is not found How to make a movie out of images in python Load local images in React.js How to install "ifconfig" command in my ubuntu docker image? How do I display local image in markdown?

Examples related to file-upload

bootstrap 4 file input doesn't show the file name How to post a file from a form with Axios File Upload In Angular? How to set the max size of upload file The request was rejected because no multipart boundary was found in springboot Send multipart/form-data files with angular using $http File upload from <input type="file"> How to upload files in asp.net core? REST API - file (ie images) processing - best practices Angular - POST uploaded file

Examples related to express

UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block jwt check if token expired Avoid "current URL string parser is deprecated" warning by setting useNewUrlParser to true MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017] npm notice created a lockfile as package-lock.json. You should commit this file Make Axios send cookies in its requests automatically What does body-parser do with express? SyntaxError: Unexpected token function - Async Await Nodejs Route.get() requires callback functions but got a "object Undefined" How to redirect to another page in node.js

Examples related to mongoose

Querying date field in MongoDB with Mongoose Server Discovery And Monitoring engine is deprecated Avoid "current URL string parser is deprecated" warning by setting useNewUrlParser to true Mongodb: failed to connect to server on first connect Push items into mongo array via mongoose Mongoose: findOneAndUpdate doesn't return updated document mongoError: Topology was destroyed Difference between MongoDB and Mongoose How can you remove all documents from a collection with Mongoose? E11000 duplicate key error index in mongodb mongoose