Node.js LogoWhen it comes to the UI, file uploads are pretty simple. But on the back-end, there is some work to do. Multer is a Node.js module that simplifies this process.

Uploading a file is a common task for Web applications. Today, most Web pages leverage AJAX — which requires JavaScript — for a smoother user experience, but this can be accomplished using only HTML and zero JavaScript. The truth is, HTML-only file uploads have been possible for more than 20 years. I mention this to point out that in the browser, file uploads are simple and require only a small amount of HTML. This is only half of the equation, however, because a file upload is useless without some back-end code that can process the file. So, in this article I’ll show you how to process a file upload in your Node.js application. To simplify the back-end code needed to handle a file upload, we’ll leverage Multer, a Node.js middleware for handling multipart/form-data.

For this article, our working example code is a simple Node application that accepts a POST request with an “enctype” of “multipart/form-data.” When the user uploads a file, our back-end code will take the uploaded file and put it in the “uploads” folder, right within the root of the project folder. Nothing too fancy here, but it’s worth noting that the examples provide plenty of opportunities for copy/paste. What you do with these examples is up to you, but at least you’ll know how to process a file upload in your Node application.

index.html

In the above example (index.html), we have the HTML file for our application, so take a look at the form element. You’ll see that the “enctype” attribute is set to “multipart/form-data,” which means that we will send images in various formats. This is also important to keep in mind because Multer will only process this kind of file-upload. Note also the input element, which has a type attribute of “file.” This ensures that the browser will take care of implementing a file-upload interface. So, in other words, there will be a “Choose File” button, which allows the user to select a file from his or her hard drive. We certainly don’t need to put any effort into this; simply setting type=“file” takes care of all of it. There is also a name attribute for this input element. This attribute is required so that Multer understands how to handle the request. The Submit button will pass the form to the same exact URL because there is no “action” attribute, so the default behavior is: this is the form submitted to the same exact URL.

Configuring Multer – Example # 1

Example # 1 contains all of the code for our Node application. For this project, we leverage the Express framework. By using Express, we significantly reduce the amount of code needed. One of the most powerful features of Express is the ability to easily create middleware, which is a perfect context for Multer because it needs to intercept the HTTP request for us. The upload variable is used to provide configuration for Multer. In this case, for example, it lets Multer know that we want our uploaded files to be placed in the “uploads” folder. We’re using express.static in order to serve the HTML and CSS files to the user, so when the user goes to the “/” route, index.html and style.css are served by the Express framework.

Adding a Handler for the POST route

On Line # 11, we set up a handler for the POST route. If you’ve ever used the Express framework when building a Node application, this pattern should look familiar to you. But notice that the second argument passed to the app.get() method is upload.single(‘img’). We’re using the upload variable created earlier. The single() method takes a string as an argument, which is the “name” attribute of the form field containing the uploaded file. For demonstration purposes, we output req.file to the console so we can see information on the uploaded file. We call the send method of the response object, passing it some HTML, which simply informs the user that the upload was successful and allows that user to go back to the “/” route.

At this point, it would be a good idea to run the example code yourself, so just follow these steps:

  • git clone
  • git@github.com:kevinchisholm/video-code-examples.git
  • cd /node/file-uploads-with-multer/
  • npm install
  • node index
  • Open this URL in your browser: http://localhost:3000/

Now in your browser, click the “Choose File” button and browse your hard drive for a file to upload. Once you’ve selected a file, click the “Submit” button. You should see the message: “File upload succeeded.” Now, if you look in the “uploads” folder in the root of the project folder, you should see a file with a name similar to: “08e36ff4c9d3dc106e3a9fa2367797c9”.

So, we’ve made good progress here; our example code works and we’re able to upload a file. As you can see, though, the original name of the file is not preserved, and a GUID-like name is provided. This can be helpful in that users will not overwrite a file when uploading the same-named file more than once. The downside, however, is that there’s no connection between the original file name and the one provided. So, let’s fix that.

Show the Original File Name – Example # 2

Stop the Node application and then start it again, using the second example: node index2. Now, upload a file again.
You’ll see that the original file name is preserved.
In Example # 2, we accomplished this by leveraging multer.diskStorage(). When calling that method, we provided a configuration object. The destination property told multer.diskStorage() where the uploaded file will go, and the filename property provided a way for us to specify what the name of the uploaded file will be. This method receives a second argument called file, so we use the “originalname” property of this object to set the file name. But there’s a new problem now: the user can overwrite an uploaded file by uploading a file with the same name. So let’s fix that.

Create a Dynamic File Name – Example # 3

In Example # 3, we have expanded the anonymous function passed to the filename() method. What we’ve done here is use regular expressions to extract the name of the file with and without the extension. We use Date.now() to generate what is essentially a unique value, and we piece the new file name back together. As a result, the user can upload the exact same file over and over, but each uploaded file name will be unique. For example: original-file-name_123456.jpg. So, let’s just confirm this. Stop the Node application and then start it again, using the third example: node index3. Now, upload the same file over and over. You’ll see that each uploaded file has a unique name, but the original file name is included so that it’s easy to reference the actual file that was uploaded.