DEV Community

Cover image for Image Upload Using Cloudinary + Multer in React.js & Node.js
Ishwor karki
Ishwor karki

Posted on

Image Upload Using Cloudinary + Multer in React.js & Node.js

๐Ÿ“ธ Image Upload Using Cloudinary + Multer in React.js & Node.js

Handling image uploads is something almost every web app needs to deal with โ€” whether you're building an e-commerce platform, a blog, or a portfolio site. In this post, Iโ€™ll walk you through a simple and practical way to upload images from a React frontend to Cloudinary, using Multer in a Node.js + Express backend.

Letโ€™s get started! ๐Ÿš€


๐Ÿงฐ What Weโ€™re Using

  • Frontend: React.js
  • Backend: Node.js + Express.js
  • Middleware: Multer
  • Cloud Storage: Cloudinary

๐Ÿค” Why Use Cloudinary?

Cloudinary makes image management incredibly easy and efficient. Hereโ€™s why I chose it:

  • โœ… Automatically optimizes images for web delivery
  • โœ… Handles storage, transformation, and CDN delivery out of the box
  • โœ… Free tier is great for small apps or portfolios
  • โœ… Easy integration with Node.js and other platforms

You donโ€™t have to worry about where images are stored, how they are served, or resizing them manually. Cloudinary handles all that for you.


โœ… Step 1: Set Up Cloudinary

  1. Go to cloudinary.com and create a free account.
  2. Open your Dashboard.
  3. Take note of your Cloud name, API key, and API secret โ€” youโ€™ll need them soon.

๐Ÿงฑ Step 2: Backend Setup (Node.js + Express)

๐Ÿ”ธ 1. Install the packages

npm install express multer cloudinary dotenv cors
npm install multer-storage-cloudinary
Enter fullscreen mode Exit fullscreen mode

๐Ÿ”ธ 2. Create .env file

At the root of your project, create a .env file:

CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก Tip: Make sure to add .env to your .gitignore so you donโ€™t commit your secrets.


๐Ÿ”ธ 3. Create server.js

import express from "express";
import cors from "cors";
import dotenv from "dotenv";
import uploadRouter from "./routes/uploadRoute.js";

dotenv.config();

const app = express();
app.use(cors());
app.use(express.json());
app.use("/api/upload", uploadRouter);

const PORT = 8000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Enter fullscreen mode Exit fullscreen mode

๐Ÿ”ธ 4. Cloudinary Config - config/cloudinaryConfig.js

import { v2 as cloudinary } from "cloudinary";
import dotenv from "dotenv";

dotenv.config();

cloudinary.config({
  cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
  api_key: process.env.CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET,
});

export default cloudinary;
Enter fullscreen mode Exit fullscreen mode

๐Ÿ”ธ 5. Upload Route - routes/uploadRoute.js

import express from "express";
import multer from "multer";
import { CloudinaryStorage } from "multer-storage-cloudinary";
import cloudinary from "../config/cloudinaryConfig.js";

const router = express.Router();

const storage = new CloudinaryStorage({
  cloudinary,
  params: {
    folder: "uploads",
    allowed_formats: ["jpg", "png", "jpeg"],
  },
});

const upload = multer({ storage });

router.post("/", upload.single("image"), (req, res) => {
  res.status(200).json({
    message: "Upload successful",
    imageUrl: req.file.path,
  });
});

export default router;
Enter fullscreen mode Exit fullscreen mode

๐ŸŽจ Step 3: React Frontend

Hereโ€™s the UI component for selecting, previewing, and uploading the image.

๐Ÿ”ธ ImageUploader Component

import React, { useState } from "react";
import axios from "axios";

const ImageUploader = () => {
  const [image, setImage] = useState(null);
  const [preview, setPreview] = useState("");
  const [url, setUrl] = useState("");

  const handleFileChange = (e) => {
    const file = e.target.files[0];
    setImage(file);
    setPreview(URL.createObjectURL(file));
  };

  const handleUpload = async () => {
    const formData = new FormData();
    formData.append("image", image);

    try {
      const res = await axios.post("http://localhost:8000/api/upload", formData);
      setUrl(res.data.imageUrl);
    } catch (error) {
      console.error("Upload failed:", error);
    }
  };

  return (
    <div>
      <h2>Upload an Image</h2>
      <input type="file" onChange={handleFileChange} accept="image/*" />
      <button onClick={handleUpload}>Upload</button>

      {preview && <img src={preview} alt="Preview" width="200" />}
      {url && (
        <div>
          <p>Uploaded Image URL:</p>
          <a href={url} target="_blank" rel="noopener noreferrer">{url}</a>
        </div>
      )}
    </div>
  );
};

export default ImageUploader;
Enter fullscreen mode Exit fullscreen mode

๐Ÿš€ What You Get

  • โœ… A React UI that previews the image before upload
  • โœ… Images uploaded and stored in Cloudinary
  • โœ… The image URL returned and displayed

๐Ÿงผ Bonus Tip

Only allow image files with this:

<input type="file" accept="image/*" />
Enter fullscreen mode Exit fullscreen mode

๐Ÿ™Œ Final Thoughts

We just built a real-world image upload feature with:

  • โš™๏ธ Multer to process file uploads
  • โ˜๏ธ Cloudinary to store and optimize them
  • โš›๏ธ React to build the user interface

This setup is clean, scalable, and ready to be reused in any modern project. Whether youโ€™re working on a blog, CMS, or e-commerce platform โ€” this pattern will save you time and keep your codebase organized.


Thanks for following along โ€” and happy coding! โœจ

Top comments (1)

Collapse
 
ramcpucoder profile image
Ram Kumar Dhimal โ€ข

loved it

close