Uploading files locally with Node & Express

File uploading is a requirement for a lot of web apps. Most of them at least need to be able to upload some pictures.

Unfortunately, out of the box neither Node nor Express supports file uploading. Moreover, it is not trivial to implement this feature from scratch.

However, there are some solutions which can help you. Let’s look at one very simple way to implement file uploading to local folder of your server.

Starting Point

Let’s assume that you have the following application structure.

project/
  controllers/
    index.js
    pictures.js
  models/
  public/
    uploads/
  views/
  app.js

It’s a classical MVC structure. Controllers contain your request handlers, models handle your data and business logic, and views define all page templates. Public contains all publicly accessible static files like images, front-end JavaScript and stylesheets.

In this example, you are going to upload files to the public/uploads/ folder.

Initially your pictures.js controller looks like this.

var express = require('express')
  , router = express.Router()

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

})

module.exports = router

It has only one request handler, which handles all POST requests to pictures/upload. This is where you will handle your files.

However, before you go further with the file handling let’s first create a simple form which is capable of sending files from the browser to your server. You should place the following snippet of HTML when you need file upload.

<form action="/pictures/upload" method="POST" enctype="multipart/form-data">
  Select an image to upload:
  <input type="file" name="image"> 
  <input type="submit" value="Upload Image">
</form>

It uploads files directly to pictures/upload just where you expect them. Moreover it has the following attribute enctype="multipart/form-data". Without it, your form will not be able to upload files to the server.

There is just one more thing to have in mind. You have put the name image to your input element of type file. Remember it, you will see in a minute why it is important.

For the actual file uploading you are going to use one additional NPM module called multer. It makes file uploading to a local folder a breeze.

It has a ton of features, but my favorite one is that it automatically renames files when uploading so that there is no file collision and no file overwrites any other.

Install it with NPM.

$ npm install multer

multer is a middleware, which when it sees a post request from a form with enctype="multipart/form-data" understand that there is a file to be uploaded.

In your code you want only the /pictures/upload path to handle file uploads, so this is where you are going to use your new middleware.

var express = require('express')
  , router = express.Router()
  , multer = require('multer')

var uploading = multer({
  dest: __dirname + '../public/uploads/',
})

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

})

module.exports = router

Now, whenever a file is submitted from your form it is automatically saved in the public/uploads folder. This happens even before your request handler is called.

Your new middleware provides you with a few useful objects inside the request handler. In req.files you have access to all files uploaded with the current request.

Do you remember that you gave the name picture to the input element of type file above? Now you can access all of its properties from req.files.picture. Easy.

What properties you ask, well here they are:

  • originalname - Name of the file on the user’s computer
  • name - Renamed file name
  • encoding - Encoding type of the file
  • mimetype - Mime type of the file
  • path - Location of the uploaded file
  • extension - Extension of the file
  • size - Size of the file in bytes
  • truncated - If the file was truncated due to size limitation
  • buffer - Raw data (is null unless the inMemory option is true)

You can use them for example to create a new record in your database for the new image. However, bare in mind, that at this point the image is already uploaded in the folder.

Limits

File uploading is cool and you can leave your code like that, but there are some potential problem. Someone could upload a 1TB file which will not only fill your entire hard drive, but it can also choke to death your entire server.

Thanks to some of the built-in features of multer, you can easily fix this problem.

var express = require('express')
  , router = express.Router()
  , multer = require('multer')

var uploading = multer({
  dest: __dirname + '../public/uploads/',
  limits: {fileSize: 1000000, files:1},
})

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

})

module.exports = router

With this configuration in place, you have limited to uploading at most 1 file at a time and of size no more than 1MB.

Disadvantages of local file uploading.

You want upload files, but sometimes uploading them locally is not so good idea. First and most, all hard drives have a limit. It might be 1MB, 1GB or 1TB but there is always a limit and sometimes your application should be able to store an unlimited number of files of almost any size.

Handling this is a complicated task. Moreover, even if you implement such a system, there is another serious problem. File redundancy. What if a hard disk fails? You don’t want to lose precious data.

Creating this file redundancy is hard and difficult task, too.

Advantages

The first advantage is that implementing uploading files to a local fodler is easy, just a few lines.

Then you also have very fast access to files, which especially critical if you need to do some file processsing.

When you talk about file processing, it is simpler to proces a file stored locally than one stored on a remote server.

Next

Your next step should be to learn more about multer and its other useful features.

Once you reach its limits, your next step should be learn about S3. The wonderful service by Amazon Web Services, which can handle an unlimited number of files of virtually any size.

Not only that, but once they are stored in S3 they can either be accessed programatically with very simple API or S3 can serve them directly to your users over HTTP or HTTPS. As a result all the heavy traffic will not be on your servers.


Other articles that you may like

Did you like this article?

Please share it

We are Stefan Fidanov & Vasil Lyutskanov. We share actionable advice about development with Node, Express, React and other web & mobile technologies.

It is everything that we have learned from years of experience working with customers from all over the world on projects of all sizes.

Let's work together
© 2024 Terlici Ltd · Terms · Privacy