How to Upload Download Files in Node.js Using Express, Multer and MongoDB

Handling file uploads is a core requirement for many web applications—whether you are building an e-commerce store for product images, a profile picture uploader, or an inventory management system.

In this tutorial, we will walk through how to build a complete file upload pipeline from scratch using Node.js, Express, Multer (for handling multipart form data), EJS (for server-side rendering), and Mongoose (to store file paths and metadata in MongoDB).

Prerequisites & Tech Stack

Make sure you have Node.js and MongoDB installed on your system. We will use the following packages:

  • Express: Fast web framework for handling server routes and requests.

  • EJS: Template engine used to render dynamic HTML views.

  • Body-Parser: Middleware to parse incoming form request bodies.

  • Multer: Middleware specifically designed for handling multipart/form-data file uploads.

  • Mongoose: Object Data Modeling (ODM) library to connect and interact with MongoDB.


Step 1: Setup Your Project Directory

Open your console or terminal and create a new folder for your project, then navigate inside it using these commands:
mkdir UploadDownload
cd UploadDownload

Step 2: Initalize Package.Json

Initialize your Node.js environment automatically by running the following command in your terminal:                   

npm init -y

This creates a package.json file, which tracks your project's metadata and installed dependencies.

Step 3: Install Required Dependencies

Install all the necessary packages for your application in a single command:

npm install express ejs body-parser multer mongoose

Once installed, a node_modules folder will be generated, and your package.json dependencies list will automatically update.

Step 4: Configure Project Structure and Entry Point

  • Create a new file in your project root directory named app.js.

  • Open your package.json file and make sure your scripts object includes a start command: "start": "node app.js".

  • Create the required folder structure so your server knows where to store files and view templates:

    • views/ (Contains your frontend template files, such as home.ejs)

    • public/uploads/ (Static folder where uploaded files will be physically saved on your server disk)

Step 5:Write the Backend Logic(app.js)

  • Open your app.js file and add the following code. This file ties together your Express server, MongoDB connection via Mongoose, and Multer file storage configuration.

var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var multer =  require('multer');
var path = require('path');

var picSchema= new mongoose.Schema({
    picpath:String
})

var picModel = mongoose.model('picsdemo',picSchema);

var storage = multer.diskStorage({
    destination:function(req,file,cb){
        cb(null,'./public/uploads')
    },
    filename:function(req,file,cb){
        cb(null,file.originalname)
    }
})
var upload = multer({storage:storage})

var app = express();

mongoose.connect('mongodb://localhost:27017/pics',{useNewUrlParser:true})
.then(()=>console.log('connected')).catch(err=>console.log('error ocured',err));

app.set('views',path.resolve(__dirname,'views'));
app.set('view engine','ejs');

var pathh = path.resolve(__dirname,'public');
app.use(express.static(pathh));
app.use(bodyParser.urlencoded({extended:false}));


app.get('/',(req,res)=>{
    picModel.find((err,data)=>{
        if(err){
            console.log(err)
        }
        else if(data.length>0){
            res.render('home',{data:data})
        }
        else{
            res.render('home',{data:{}})
        }
    })
})

app.post('/',upload.single('pic'),(req,res)=>{
    var x = 'uploads/'+req.file.originalname;
    var temp = new picModel({
        picpath:x
    })
    temp.save((err,data)=>{
        if(err){
            console.log(err)
        }
        res.redirect('/')
    })
})

app.get('/download/:id',(req,res)=>{
    picModel.find({_id:req.params.id},(err,data)=>{
         if(err){
             console.log(err)
         }
         else{
             var x= __dirname+'/public/'+data[0].picpath;
             res.download(x)
         }
    })
})

var port  = process.env.PORT || 3000 ;
app.listen(port,()=>console.log('server running at port'+port))

How the Backend Code Works:

  • mongoose.connect(): Establishes a connection to your local MongoDB instance (mongodb://localhost:27017/picspics). The database will be created automatically on your server when data is first inserted.
  • app.set("views", ...): Tells Express where to locate your template views folder.
  • app.set("view engine", "ejs"): Instructs Express to render files ending in .ejs using the EJS engine.
  • body-parser: Parses incoming request bodies so you can easily access form input fields.
  • Mongoose Schema & Model: Defines the structure (fields) of your collection (mongoose.Schema({})) and registers the model (mongoose.model()).
  • upload.single('pic'): This is the core Multer middleware. The string 'pic' must match the name attribute of your file input tag in your HTML form (<input type="file" name="pic">).

  • diskStorage: Tells Multer to save uploaded files into the ./public/uploads directory while keeping their original filenames.

  • res.download(): Express built-in helper method that triggers a file download prompt in the user's browser for the specified file path.

Step 6: Create the Frontend View Template (views/home.ejs)

Create a file named home.ejs inside your views/ directory. This file provides a clean user interface with a form to upload files and a gallery grid to display previously uploaded files with download buttons.

 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <title>Document</title>
 </head>
 <body>
      <form action="/" method="POST" enctype="multipart/form-data">
      <input type="file" name="pic" id="pic"><br>
      <input type="submit" value="upload file">
    </form><br><br><br><br>
    <% if(data.length > 0) {%>
      <table>
           <thead>
               <tr>
                   <td>
                       images
                   </td>
                   <td>
                       download
                   </td>
               </tr>
           </thead>
           <tbody>
               <% for(var i=0; i< data.length; i++) {%>
               <tr>
                   <td>
                 <img src="<%= data[i].picpath%>" alt="images" style="width:100px; height:100px;">
                   </td>
                   <td>
                <form action="/download/<%= data[i]._id%>">
                 <input type="submit" value="download">
                </form>
                   </td>
               </tr>
               <% } %>
           </tbody>
      </table>
      <% } %>  
 </body>
 </html>

Step 7: Run and Test Your Application

  • Start your application from your terminal:
        node app.js
  • Open your web browser and go to:
         http://localhost:3000
  • Select an image file, click Upload File, and watch it instantly save to your server disk and appear in your gallery!

References & Source Code

Comments

Popular posts from this blog

How to Setup a Flask Project in Python: Step-by-Step Guide

How to Use Sequelize-CLI to Create Tables and Relationships in Node.js

How to Upload Images in Node.js and Express Using AJAX and jQuery