How To Make A Basic HTML Form Upload Files To Your Server Using Multer In A Node.js/Express App

Jesse Lewis
6 min readNov 16, 2017

--

What we are building today.

Recently I decided to tackle the concept of enabling my express web app’s users to upload their own photos to their account for their profile avatars and the products they will be uploading. If you want to do the same and are considering using Node.js/Express then keep reading.

How I think my App should make that happen
On the back end I want to store their photos in a cloud storage solution and then store data about their images into my MongoDB database. (such as it’s url, file size, width and height proportions, and other snazzy things like common hex format of base colors the image contains to build incredible search tools with)

NOTE: This tutorial covers only the YELLOW portions

Sounds easy enough, right!? …Bwahaha!

Dreaming of code I will write for this…
A. Upload’s user photos to a temporary storage folder on my server (What this tutorial covers)
A user uploads a photo, my backend places it in a local folder and provides a url to that local storage location.

B. My app then transfer’s that file to the cloud (using AJAX)
My backend server then takes that photo and places it in cloud storage via AJAX post request, with a callback that includes the url of the file in the cloud.

C. My app receives the url of the photo’s cloud location and then post’s data about the photo and my user into my Mongo Database.
When that completes, I post all the relevent data with that URL into my app’s database — and make all sorts of cool magic happen!

Included in this tutorial

After vetting and sampling (way too many useless) solutions while stress eating chocolate chip cookies, I finally came across an example that actually worked for part A of this code dream I have and so I became compelled to write this tutorial for all the rest of us online stress eating cookies and wanting to solve this.

  • A fabulous link to my demo repo from github!
    https://github.com/Lazercat/node-express-file-form-upload-demo
  • A considerate expectation that you already know how to create / configure a node.js/express web app.
  • A sparkling disclaimer of how this only includes very basic file polishing and you are responsible (like usual) for implementing your own security solutions. This solution works, but I don’t claim to be a security expert.
  • fantastic screenshots and nerdy code review of what we are building!

Using my demo project file (like a boss)

1FORK /CLONE
Get over to github and clone or fork/clone… (if you want to help me make it better, (yes, please!)) … my demo repository for this solution. https://github.com/Lazercat/node-express-file-form-upload-demo.

2INSTALL NPM PACKAGES
Once cloned locally, run an npm install from your command line (bash/terminal) in the root folder where App.js is.

npm install

3RUN THE APP
I included the nodemon package in this project, so to run this solution on your localhost just type the following code. As you make changes, nodemon will automatically re-run it for you -neato, huh?

nodemon App.js 

4 Visit http://localhost:3000 in your web browser to check out this smokin’ hot solution!

Let’s review the app dependencies! (like a nerd)

Part 1) YOUR APP.JS SERVER dependencies and basic setup.

/* App.js file */ // RUN PACKAGES
const express = require('express'); //app router
const multer = require('multer'); // file storing middleware
const bodyParser = require('body-parser'); //cleans our req.body
// SETUP APP
const app = express(); //This IS an express app
const port = process.env.PORT || 3000; //preconfig your port!
app.use(bodyParser.urlencoded({extended:false})); //handle body requests
app.use(bodyParser.json()); // let's make JSON work too!
app.use('/', express.static(__dirname + '/public'));
//let's declare a public static folder,
// this is where our client side static files/output go
  1. Express — lovely express, an incredibly fast web framework package that provides our routing solution in this demo. make sure to include it as shown above and to set your app to = express.
    Official Documentation: https://www.npmjs.com/package/express
  2. Multer — A node package for handling multipart/form-data enctypes (nerd jargon for an html form that submits files) and also the nuts and bolts of this solution!
    Official documentation: https://www.npmjs.com/package/multer
  3. Body Parser — This incredibly lovely tool cleans up and prepares the req.body object passed by our routes (and form) and makes our lives easier!
    Official documentation: https://www.npmjs.com/package/body-parser

Configuring Multer (like a youtube tutorial I found)

The reason all of this is possible is because of the following code, more so than the other basics I will walk you through. My inspiration for this post is web developer, Ashish Mehra, who provides an excellent walkthrough and then some, here: (https://www.youtube.com/watch?v=sMnqnvW81to&lc=z23htp54jwmhwni0nacdp43axbwhgu3y3fg0jwzwhatw03c010c).

This is what I was able to implement because of Ashish’s awesome findings.

/* in App.js file *///MULTER CONFIG: to get file photos to temp server storage
const multerConfig = {

storage: multer.diskStorage({
//Setup where the user's file will go
destination: function(req, file, next){
next(null, './public/photo-storage');
},

//Then give the file a unique name
filename: function(req, file, next){
console.log(file);
const ext = file.mimetype.split('/')[1];
next(null, file.fieldname + '-' + Date.now() + '.'+ext);
}
}),

//A means of ensuring only images are uploaded.
fileFilter: function(req, file, next){
if(!file){
next();
}
const image = file.mimetype.startsWith('image/');
if(image){
console.log('photo uploaded');
next(null, true);
}else{
console.log("file not supported");

//TODO: A better message response to user on failure.
return next();
}
}
};

The HTML Form

What makes a good form to upload a file? Answer — one that can actually handle it. Your typical html form is used for handling data, not documents. To get a file to post you need two setup 4 critical things, also displayed in bare-bones code below:

  1. change the enctype of the form to ‘multipart/form-data’, an encode type that Multer happens to handle really well.
  2. give yourself a method=”POST”
    (sort-of a given, but critical to our success.)
  3. An action that posts to a route action=”/upload” (more on this below)
  4. have an html input with type=”file” AND name=”photo”
<!-- public/index.html file -->
<form action="/upload" enctype="multipart/form-data" method="POST">
<input type="file" name="photo" />
<input type="submit" value="Upload Photo"/>
</form>

The Router

Let’s finish this lovely situation by handling the route/controller for where the server pushes this code, Special Trick: while calling multerConfig! (see route 2 below).

/* in App.js File */ //Route 1: serve up the homepageapp.get('/', function(req, res){
res.render('index.html');
});
//Route 2: serve up the file handling solution (it really needs a better user response solution. If you try uploading anything but an image it will still say 'complete' though won't actually upload it. Stay tuned for a better solution, or even better, build your own fork/clone and pull request it back to me so we can make this thing better together for everyone out there struggling with it. app.post('/upload',multer(multerConfig).single('photo'),function(req,res){
res.send('Complete!');
});
// Please note the .single method calls ('photo'), and that 'photo' is the name of our file-type input field!

The Server

Well… this web app won’t work if it doesn’t have one. So hyg!

/* in App.js file */app.listen(port,function(){
console.log(`Server listening on port ${port}`);
});

The Output/Solution (Finally..)

Grab your popcorn and be mesmerized by these screenshots!

User choose’s file to load a picture, then clicks ‘Upload Photo’
A confirmation message returned with res.send from the router.
Check out these cool photos getting uploaded to your local server!

--

--

Jesse Lewis
Jesse Lewis

Written by Jesse Lewis

Full Stack Software Engineer | Digitizer of Dreams

Responses (5)