Upload images to AWS S3 using multer in node.js
Paras 🧙‍♂️

Paras 🧙‍♂️ @paras594

About: Senior Frontend Engineer & Certified Neo4j Professional with 7 years of experience. Love to learn and build new things. When not coding, you can find me exploring new tech, games & books.

Location:
Delhi, India
Joined:
Feb 19, 2019

Upload images to AWS S3 using multer in node.js

Publish Date: Jul 13 '22
31 4

Multer is a node.js middleware and it handles multipart/form-data that includes files, images etc.

It mostly occurs in projects that we need to handle file uploads in our APIs. We can save those files in local disk storage on our system, but its better to have a hosted platform where we can upload our files and access through anywhere using the link. One such cloud storage is AWS S3.

In this post, we will be uploading images to S3 storage using multer. Likewise, you can handle any kind of file you like. Also, we will learn to use the version 3 of AWS sdk, which has a little different setup than the previous version.

Prerequisites

  1. Basics of node.js and express

Setup AWS Account

  1. Create an account on AWS.
  2. There should be services tab/link. From there, we can select S3. It will be empty but we will be able to see objects in it once we start uploading files in it.
  3. Grab your access keys from your files in credentials section. You should have access key id and secret key. We will use these when configuring multer.
  4. Choose your AWS region as per your location and take a note of its region id.

Setup Multer

To connect with AWS S3, we need its SDK and multer-s3 package. We will be using AWS SDK V3.

Install Multer, multer-s3 and aws sdk

$ npm install --save multer multer-s3 @aws-sdk/client-s3
Enter fullscreen mode Exit fullscreen mode

Create multer middleware

In your middlewares folder, create a file uploadImage.js. You can name it anything you like.

Step 1: In uploadImage.js, we will setup the S3 client:

const multer = require("multer");
const multerS3 = require("multer-s3");
const { S3Client } = require("@aws-sdk/client-s3");

// create s3 instance using S3Client 
// (this is how we create s3 instance in v3)
const s3 = new S3Client({
    credentials: {
        accessKeyId: "YOUR_ACCESS_KEY_ID_HERE", // store it in .env file to keep it safe
        secretAccessKey: "YOUR_SECRET_KEY_HERE"
    },
    region: "ap-south-1" // this is the region that you select in AWS account
})
Enter fullscreen mode Exit fullscreen mode

Step 2: In uploadImage.js, add the following. use multer-s3 to connect to client and create s3 storage for multer

const s3Storage = multerS3({
    s3: s3, // s3 instance
    bucket: "my-images", // change it as per your project requirement
    acl: "public-read", // storage access type
    metadata: (req, file, cb) => {
        cb(null, {fieldname: file.fieldname})
    },
    key: (req, file, cb) => {
        const fileName = Date.now() + "_" + file.fieldname + "_" + file.originalname;
        cb(null, fileName);
    }
});
Enter fullscreen mode Exit fullscreen mode

Step 3: Using our storage instance to create our uploadImage middleware using multer

// function to sanitize files and send error for unsupported files
function sanitizeFile(file, cb) {
    // Define the allowed extension
    const fileExts = [".png", ".jpg", ".jpeg", ".gif"];

    // Check allowed extensions
    const isAllowedExt = fileExts.includes(
        path.extname(file.originalname.toLowerCase())
    );

    // Mime type must be an image
    const isAllowedMimeType = file.mimetype.startsWith("image/");

    if (isAllowedExt && isAllowedMimeType) {
        return cb(null, true); // no errors
    } else {
        // pass error msg to callback, which can be displaye in frontend
        cb("Error: File type not allowed!");
    }
}

// our middleware
const uploadImage = multer({
    storage: s3Storage,
    fileFilter: (req, file, callback) => {
        sanitizeFile(file, callback)
    },
    limits: {
        fileSize: 1024 * 1024 * 2 // 2mb file size
    }
})

module.exports = uploadImage;
Enter fullscreen mode Exit fullscreen mode

Using uploadImage middleware in routes

Lets create a route where a user can update his profile image. I assume express and router is already setup.

// update profile image
router.put(
    "/:userId/profile-image", 
    uploadImage.single("image"), // our uploadImage middleware
    (req, res, next) => {
        /* 
           req.file = { 
             fieldname, originalname, 
             mimetype, size, bucket, key, location
           }
        */

        // location key in req.file holds the s3 url for the image
        let data = {}
        if(req.file) {
            data.image = req.file.location
        }

        // HERE IS YOUR LOGIC TO UPDATE THE DATA IN DATABASE
    }
)
Enter fullscreen mode Exit fullscreen mode

So, this was it for using multer with AWS and v3 SDK. I hope you find it helpful.

✌️

Comments 4 total

  • sumit ruhela
    sumit ruhelaMay 22, 2023

    uploadImage.single("image"), // our uploadImage middleware
    ^

    TypeError: Cannot read property 'single' of undefined

    getting this error

    • Robbie Mariano
      Robbie MarianoJul 15, 2023

      uploadImage was declared before, specifically this one
      Image description

  • vijay
    vijayDec 27, 2023

    is there a way to show upload progress with this approach?

    • Paras 🧙‍♂️
      Paras 🧙‍♂️Jan 1, 2024

      I don't think there is a way. Never did this. Will let you know once I try it. Do share if you get the answer.

Add comment