October 30, 2026
How to Upload and Download Files in Node.js Using Express & Multer.
In this tutorial, we will build a complete file upload pipeline using Node.js, Express, Multer (for handling multipart/form-data), EJS (for…

By Ashwani Bakshi
3 min read
In this tutorial, we will build a complete file upload pipeline using Node.js, Express, Multer (for handling multipart/form-data), EJS (for server-side rendering), and Mongoose (to store file metadata in MongoDB).
To learn more about how middleware works under the hood, you can explore the official Multer documentation.
Step 1: Setup Your Project Directory
- create a new folder using console/terminal.
- open console/terminal type mkdir followed by the folder name you want to give.
- change to that folder by typing cd folder name.
Step 2: Initialize package.json
- You can initialize your project automatically using npm, or create the configuration file manually:
- Automated Setup: Run
npm initin your terminal and follow the prompts. - Manual Setup: Alternatively, create a file named
package.jsonin your root directory and structure it manually with your project dependencies and entry point. - Your
package.jsonwill look similar to this once configured:
Step 3: Install Required Dependencies
- now we will install packages for our project using npm install followed by package names we want to install.
- the following packages will be installed express ejs body-parser multer mongoose.
express: Web framework for handling server routes and requests.ejs: Template engine used to render HTML views dynamically.body-parser: Middleware to fetch and parse incoming form data.multer: Middleware specifically designed for handlingmultipart/form-datafile uploads.mongoose: ODM library to connect and interact with MongoDB.
Step 4: Configure Project Structure and Entry Point
- Create a new file in your root directory named
app.js. - Open your
package.jsonand ensure yourscriptsobject has a start command:"start": "node app.js". This serves as your application entry point..
Step 5: Understanding app.js and Database 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))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))Your app.js file ties together the Express server, MongoDB connection via Mongoose, and Multer middleware. Here is a breakdown of the key configurations:
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.ejsusing 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'): The core Multer middleware handler. The string'pic'must match thenameattribute of your file input tag in the frontend form (<input type="file" name="pic">).
Step 6: Create the Required Folder Structure
views/(Contains your frontend template files, e.g.,home.ejs)public/uploads/(Static folder where uploaded files will be stored on the server disk)
- home.ejs
<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> <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>GitHub - ashwanibakshi/fileuplloaddownload Contribute to ashwanibakshi/fileuplloaddownload development by creating an account on GitHub.