Multer File Uploading ULTIMATE GUIDE
Multer File Uploading ULTIMATE GUIDE

Multer is a body parsing middleware that handles content type multipart/form-data.

A Basic Usage

Don’t forget the enctype="multipart/form-data" in your form.

<form action="/profile" method="post" enctype="multipart/form-data">
  <input type="file" name="avatar" />
</form>

A Basic Express App

Prerequisite: Make sure you have a running Basic Express App.

Install

npm i multer

Create This Project Structure

  • index.js
  • multer.js
  • routes/ router.js

Initialize it / Import it

// multer.js

const multer  = require('multer') // Intialize the MULTER
const path = require('path'); // Don't forget to require 'path'

Add Destination Folder & File Name

file’s name and validation regarding the type of file. file’s destinatio folder too.

//multer.js

const multer = require('multer');
const path = require('path'); // Don't forget to require 'path'

const storage = multer.diskStorage({  
      
      destination: function (req, file, cb) {
        cb(null, path.join(__dirname, 'uploads')); // Store files in a project root's relative 'uploads' folder
       },
  
  // ImageName-2024-10-17-13-45-23.jpg [Original Name + Date + Time] // THIS IS YOUR FILE NAME
  filename: (req, file, cb) => {
    const originalName = file.originalname.split('.')[0]; // Extract name without extension
    const date = new Date();
    const formattedDate = date.toISOString().split('T')[0]; // Format: YYYY-MM-DD
    const formattedTime = date.toTimeString().split(' ')[0].replace(/:/g, '-'); // Format: HH-MM-SS

    const newFilename = `${originalName}-${formattedDate}-${formattedTime}${path.extname(file.originalname)}`;
    cb(null, newFilename);
  },
  
});

var upload = multer({ storage: storage }); // Initialize multer with the storage configuration

module.exports = upload; // Export upload middleware for use in your routes

// ------------ERROR NOTE:------------------------------------------------
//
//   Don't do this or it will give this error ( Error: ENOENT: no such file or directory, open 'C:\uploads\images-2024-10-28-20-48-10.png' )
//
//    destination: function (req, file, cb) {
//        cb(null, '/uploads')  // this is your DESTINATION FOLDER
//      },

When using route, make sure to do:

// routes/router.js

// routes/router.js

const express = require('express')
const router = express.Router()

const upload = require('../multer.js') // IMPORTING MULTER TO USE IT ( MUST DO THIS )

  //
  //  YOUR CODE OF GET, POST, PUT, DELETE ROUTES
  //

module.exports = router

And do this in index.js

const upload=require('./multer.js')
const router=require('./routes/router.js')
// index.js

const express=require('express')
const cors = require('cors')
const upload=require('./multer.js')        // (((((((( DO THIS ))))))))
const router=require('./routes/router.js') // (((((( DO THIS TOO )))))))

// Initialize Express Application
const app = express()

// Apply Middlewares
app.use(cors()) // ensure all requests respect cross-origin rules
app.use(express.json()) //parses all JSON requests/bodies going to routes
app.use('/uploads', express.static('uploads')) // serving uploads folder

// Use the routes
app.use(router)


const PORT = 8000
app.listen(PORT, () => {
    console.log(`Backend Server is running on port ${PORT}`)
});

Storing SINGLE

Using upload.single() is particularly useful when your application requires only one file upload, such as for user avatars, profile pictures, or similar use cases.

// POST route to handle image upload and form submission
app.post('/upload', upload.single('image'), (req, res) => {
  const imagePath = req.file ? req.file.path : null; // Path to the uploaded file
  const { cardTitle, brand } = req.body;

  // SQL query to insert form data and image path into MySQL
  const query = `
    INSERT INTO my_db (cardTitle, brand, displayImage, imageAddress)
    VALUES (?, ?, ?, ?)
  `;

  db.query(query, [cardTitle, brand, imagePath, req.file.filename], (err, result) => {
    if (err) {
      console.error('Error inserting data:', err);
      return res.status(500).json({ message: 'Error inserting data' });
    }

    res.json({ message: 'Product added successfully!' });
  });
});

Storing MULTIPLE

Using upload.array() is particularly useful when you need to handle multiple file uploads from a single input field, such as for gallery uploads, batch uploads, or similar functionalities.

POST ROUTE

// POST route to handle image upload and save the image paths and inputs to MySQL
app.post('/upload', upload.array('images', 11), (req, res) => {
  const files = req.files;

  // Prepare an object to hold image paths for each specified column
  const imageData = {
    displayImage: files[0] ? files[0].path : null,
    firstImage: files[1] ? files[1].path : null,
    secondImage: files[2] ? files[2].path : null,
    thirdImage: files[3] ? files[3].path : null,
    fourthImage: files[4] ? files[4].path : null,
    fifthImage: files[5] ? files[5].path : null,
    sixthImage: files[6] ? files[6].path : null,
    seventhImage: files[7] ? files[7].path : null,
    eighthImage: files[8] ? files[8].path : null,
    ninthImage: files[9] ? files[9].path : null,
    tenthImage: files[10] ? files[10].path : null,
  };

  // Extract additional input fields from the request body
  const {
    slug,
    cardTitle,
    category,
    brand,
    soldNumber,
    actualPrice,
    markedPrice,
    rating,
    freeShipping,
    stockStatus,
    title,
    description,
    bigDescription,
    specification
  } = req.body;

  // SQL query to insert image paths and other input fields into the database
  const query = `
    INSERT INTO my_db (
      displayImage, firstImage, secondImage, thirdImage, fourthImage,
      fifthImage, sixthImage, seventhImage, eighthImage, ninthImage,
      tenthImage, slug, cardTitle, category, brand, soldNumber,
      actualPrice, markedPrice, rating, freeShipping, stockStatus,
      title, description, bigDescription, specification
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `;

  // Execute the query with the values from imageData and input fields
  db.query(query, [
    imageData.displayImage, imageData.firstImage, imageData.secondImage,
    imageData.thirdImage, imageData.fourthImage, imageData.fifthImage,
    imageData.sixthImage, imageData.seventhImage, imageData.eighthImage,
    imageData.ninthImage, imageData.tenthImage,
    slug, cardTitle, category, brand, soldNumber,
    actualPrice, markedPrice, rating, freeShipping, stockStatus,
    title, description, bigDescription, specification
  ], (err, result) => {
    if (err) {
      console.error('Error saving data to database:', err);
      return res.status(500).json({ message: 'Error saving data to database' });
    }

    // Send success response
    res.json({ message: 'Images and data uploaded and saved successfully!', imageData });
  });
});

PUT ROUTE

MULTER NOTES:

req.file stores the file

req.body stores the text fields, if there were any

File has these informations:

File information

Each file contains the following information:

KeyDescriptionNote
fieldname (req.file.fieldname)Field name specified in the formEx: <input type=”file” class=”form-control-file” name=”uploaded_file” >
originalname (req.file.originalname)Name of the file on the user’s computer
encodingEncoding type of the filewhich character encoding was done in text content?
UTF-8 | ISO-8859-1 | ASCII
mimetype (req.file.mimetype)Mime type of the fileOutput: image/jpeg
size (req.file.size)Size of the file in bytes
destination (req.file.destination)The folder to which the file has been savedDiskStorage
filename (req.file.filename)The name of the file within the destinationDiskStorage
path (req.file.path)The full path to the uploaded fileDiskStorage
bufferBuffer of the entire fileMemoryStorage

Multer SINGLE

// Single file (receives only a single file)
app.post("/upload", upload.single("file"), (req, res) => {
  console.log(req.file)
  return res.send("Single file")
})

Multer ARRAY

app.post("/upload", upload.array("file", 10), (req, res) => {
  console.log(req.files)
  return res.send("Multiple files")
})

How to show images in web?

Serve uploaded Images as static files

This makes sure to serve the directory where images are stored.

// index.js

app.use('/uploads', express.static('uploads'));

// formupload.jsx (merge the code with already formupload.jsx)

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function ANYTHING() {
ย ย ย ย const [products, setProducts] = useState([]);
ย ย ย ย 
ย // Fetch product data from backend
useEffect(() => {
ย ย const fetchProducts = () => {
ย ย ย ย axios.get('http://localhost:5000/upload')
ย ย ย ย ย ย .then((response) => {
ย ย ย ย ย ย ย ย setProducts(response.data); // Store all reponse data to 'products'
ย ย ย ย ย ย })
ย ย ย ย ย ย .catch((error) => {
ย ย ย ย ย ย ย ย console.error('Error fetching products:', error);
ย ย ย ย ย ย });
ย ย };

ย ย fetchProducts(); // Call the function to fetch products
}, []);

ย ย ย ย return (
ย ย ย ย ย ย <div>
ย ย ย ย ย ย ย ย <h2>Product List</h2>
ย ย ย ย ย ย ย ย <ul>
ย ย ย ย ย ย ย ย 
ย ย ย ย ย ย ย ย ย ย {products.map((product) => (
ย ย ย ย ย ย ย ย ย ย ย <li key={product.id}>
ย ย ย ย ย ย ย ย ย ย ย ย ย ย <p><strong>Card Title:</strong> {product.cardTitle}</p>
ย ย ย ย ย ย ย ย ย ย ย ย ย ย <p><strong>Brand:</strong> {product.brand}</p>
ย ย ย ย ย ย ย ย ย ย ย ย ย ย 
ย ย ย ย ย ย ย ย ย ย ย ย {product.displayImage && (
ย ย ย ย ย ย ย ย ย ย ย ย ย ย <imgย 
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย src={`http://localhost:5000/${product.displayImage}`}ย 
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย alt={product.cardTitle}ย 
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย style={{ width: '100px' }} // Adjust size as needed
ย ย ย ย ย ย ย ย ย ย  ย ย ย />
ย ย ย ย ย ย ย ย ย ย ย ย )}
ย ย ย ย ย ย ย ย ย ย ย ย </li>
ย ย ย ย ย ย ย ย ย ย ))}
ย ย ย ย ย ย ย ย </ul>
ย ย ย ย ย ย </div>
ย ย ย ย );
ย ย }

for text

              <p><strong>Card Title:</strong> {product.cardTitle}</p>


for image

{product.displayImage && (

ย ย ย ย ย ย ย ย ย ย ย ย ย ย <imgย 
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย src={`http://localhost:5000/${product.displayImage}`}ย 
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย alt={product.cardTitle}ย 
ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย ย style={{ width: '100px' }} // Adjust size as needed
ย ย ย ย ย ย ย ย ย ย ย ย ย ย />

ย )}

For Replacing that old image —– replacing old pathname, deleting old image and adding new pathname, adding new image.

const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');

const router = express.Router();

// Configure Multer storage
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    const uniqueSuffix = `${Date.now()}-${Math.round(Math.random() * 1E9)}`;
    cb(null, `${file.fieldname}-${uniqueSuffix}${path.extname(file.originalname)}`);
  },
});

const upload = multer({ storage });

// Update image route
router.put('/update-image/:id', upload.single('image'), (req, res) => {
  const { id } = req.params;
  const newImage = req.file;

  // Simulate checking the existing image (e.g., from DB or local file path)
  const existingImagePath = `uploads/${id}.jpg`; // Assume images are stored as 'id.jpg'

  // Delete old image (optional step)
  if (fs.existsSync(existingImagePath)) {
    fs.unlinkSync(existingImagePath);
  }

  // New image is now uploaded to `uploads/` directory
  res.json({ message: 'Image updated successfully', file: newImage });
});

module.exports = router;

———————————

If you want to upload a single image at a time, then follow these steps.

Let’s Add destination folder & file name

In this, we will set file’s name, destination, add validation regarding the type of the file.

ADD DESTINATION FOLDER

METHOD 1:

If you use this method, you have to create a folder.

Create ‘uploads’ folder — here we will store the uploaded files.

// server.js

const storage = multer.diskStorage({

  destination: (req, file, cb) => {
    cb(null, "uploads/")  // destination folder
  }

})

METHOD 2:

With this method, you don’t have to create “uploads” folder, it will automatically create that folder for you.

// server.js

const fs = require('fs');

const storage = multer.diskStorage({

  destination: (req, file, cb) => {
    const dir = 'uploads/';
    if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
    cb(null, dir);
  },
  
});

Note: We need a package called “fs” so that we could have control over directory and check whether “uploads” folder exists or not — and finally create the”uploads” folder. We don’t need to install fs module because it’s built-in core module, so we can use it without any installation.

This line “if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });” checks whether the directory exists or not, if it doesn’t exist, it will create that folder.

This line “cb(null, dir);” sets the destination folder for the file given in dir variable.

ADD FILE NAME

This file name can be applicable for all files including photos, pdf documents, and videos.

Note: Because we are using path (e.g: path.extname), so we need to import that package too. You don’t need to install the path module in Node.js because it is a built-in module. You can use it directly without any installation.

const path = require('path');

Original Name + Timestamp

filename: (req, file, cb) => {
  cb(null, file.originalname.split('.')[0] + '-' + Date.now() + path.extname(file.originalname)); 
}

Output: ImageName-1727337530899.jpg

Format: [originalNameWithoutExtension]-[timestamp][originalExtension]

file.originalname.split('.')[0] - Original Name of File without extension

Date.now() - Get current timestamp in milliseconds from epoch era

path.extname(file.originalname) - Get file extension

Original Name + Date + Time

filename: (req, file, cb) => {
  const originalName = file.originalname.split('.')[0]; // Extract name without extension
  const date = new Date();
  const formattedDate = date.toISOString().split('T')[0]; // Format: YYYY-MM-DD
  const formattedTime = date.toTimeString().split(' ')[0].replace(/:/g, '-'); // Format: HH-MM-SS

  const newFilename = `${originalName}-${formattedDate}-${formattedTime}${path.extname(file.originalname)}`;
  cb(null, newFilename);
}

Output: ImageName-2024-10-17-13-45-23.jpg

ALL PIECES TOGETHER

I have used Method 2 of Destination Folder and 2nd Option for File Name.

const multer = require('multer');
const fs = require('fs'); // // Don't forget to require 'fs'
const path = require('path'); // Don't forget to require 'path'

const storage = multer.diskStorage({

  destination: (req, file, cb) => {
    const dir = 'uploads/';
    
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
    
    cb(null, dir);
  },
  
  
  filename: (req, file, cb) => {
    const originalName = file.originalname.split('.')[0]; // Extract name without extension
    const date = new Date();
    const formattedDate = date.toISOString().split('T')[0]; // Format: YYYY-MM-DD
    const formattedTime = date.toTimeString().split(' ')[0].replace(/:/g, '-'); // Format: HH-MM-SS

    const newFilename = `${originalName}-${formattedDate}-${formattedTime}${path.extname(file.originalname)}`;
    cb(null, newFilename);
  },
  
  
});


var upload = multer({ storage: storage }); // Initialize multer with the storage configuration

module.exports = upload; // Export upload middleware for use in your routes

Note: We don’t need to install fs and path modules because they are built-in core modules, so we can use them without any installation.

Output: Your files will be stored in uploads folder with file name structure [ Original Name + Date + Time ]

Creating an upload route (i.e. POST Route)

Storing SINGLE

// Single file (receives only a single file)
app.post("/upload", upload.single("file"), (req, res) => {
  console.log(req.file)
  return res.send("Single file")
})

// POST route to handle image upload and form submission
app.post('/upload', upload.single('image'), (req, res) => {
  const imagePath = req.file ? req.file.path : null; // Path to the uploaded file
  const { cardTitle, brand } = req.body;

  // SQL query to insert form data and image path into MySQL
  const query = `
    INSERT INTO my_db (cardTitle, brand, displayImage, imageAddress)
    VALUES (?, ?, ?, ?)
  `;

  db.query(query, [cardTitle, brand, imagePath, req.file.filename], (err, result) => {
    if (err) {
      console.error('Error inserting data:', err);
      return res.status(500).json({ message: 'Error inserting data' });
    }

    res.json({ message: 'Product added successfully!' });
  });
});

Storing MULTIPLE

//Multiple files ( receives several files, but we can set the maximum limit files [for ex: 10 max limit] )

app.post("/upload", upload.array("file", 10), (req, res) => {
  console.log(req.files)
  return res.send("Multiple files")
})

// POST route to handle image upload and save the image paths and inputs to MySQL
app.post('/upload', upload.array('images', 11), (req, res) => {
  const files = req.files;

  // Prepare an object to hold image paths for each specified column
  const imageData = {
    displayImage: files[0] ? files[0].path : null,
    firstImage: files[1] ? files[1].path : null,
    secondImage: files[2] ? files[2].path : null,
    thirdImage: files[3] ? files[3].path : null,
    fourthImage: files[4] ? files[4].path : null,
    fifthImage: files[5] ? files[5].path : null,
    sixthImage: files[6] ? files[6].path : null,
    seventhImage: files[7] ? files[7].path : null,
    eighthImage: files[8] ? files[8].path : null,
    ninthImage: files[9] ? files[9].path : null,
    tenthImage: files[10] ? files[10].path : null,
  };

  // Extract additional input fields from the request body
  const {
    slug,
    cardTitle,
    category,
    brand,
    soldNumber,
    actualPrice,
    markedPrice,
    rating,
    freeShipping,
    stockStatus,
    title,
    description,
    bigDescription,
    specification
  } = req.body;

  // SQL query to insert image paths and other input fields into the database
  const query = `
    INSERT INTO my_db (
      displayImage, firstImage, secondImage, thirdImage, fourthImage,
      fifthImage, sixthImage, seventhImage, eighthImage, ninthImage,
      tenthImage, slug, cardTitle, category, brand, soldNumber,
      actualPrice, markedPrice, rating, freeShipping, stockStatus,
      title, description, bigDescription, specification
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `;

  // Execute the query with the values from imageData and input fields
  db.query(query, [
    imageData.displayImage, imageData.firstImage, imageData.secondImage,
    imageData.thirdImage, imageData.fourthImage, imageData.fifthImage,
    imageData.sixthImage, imageData.seventhImage, imageData.eighthImage,
    imageData.ninthImage, imageData.tenthImage,
    slug, cardTitle, category, brand, soldNumber,
    actualPrice, markedPrice, rating, freeShipping, stockStatus,
    title, description, bigDescription, specification
  ], (err, result) => {
    if (err) {
      console.error('Error saving data to database:', err);
      return res.status(500).json({ message: 'Error saving data to database' });
    }

    // Send success response
    res.json({ message: 'Images and data uploaded and saved successfully!', imageData });
  });
});

FINSIHED !!!

Creating a Frontend for File Upload

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>File Upload</title>
</head>
<body>
  <h1>File Upload Example</h1>
  <form action="/upload" method="POST" enctype="multipart/form-data">
    <input type="file" name="file">
    <button type="submit">Upload File</button>
  </form>
</body>
</html>

form fields upload

image upload

video upload

pdf upload

folder upload

Final Code