tutorial, express.js,

Upload File di Express.js dengan Multer

Kiki/🎮🍉⌨️🍩💻 Kiki/🎮🍉⌨️🍩💻 Aug 27, 2026 · 10 mins read
Upload File di Express.js dengan Multer
Share this

Upload file — gambar profil, lampiran dokumen, thumbnail artikel — adalah fitur yang hampir selalu ada di aplikasi web. Express.js sendiri tidak bisa menangani multipart/form-data (format yang digunakan untuk upload file) secara bawaan. Kita butuh middleware bernama Multer.

Di artikel ini kita bangun fitur upload gambar lengkap dengan validasi tipe file, batasan ukuran, dan penyimpanan terorganisir.


Apa itu Multer?

Multer adalah middleware Node.js untuk menangani multipart/form-data. Multer menambahkan objek body dan file (atau files) ke objek req.

npm install multer

Upload Dasar — Simpan ke Disk

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

// Konfigurasi storage
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');  // folder tujuan
  },
  filename: (req, file, cb) => {
    // Buat nama file unik: timestamp-namaasli.ext
    const ext = path.extname(file.originalname);
    const namaUnik = `${Date.now()}-${Math.round(Math.random() * 1e9)}${ext}`;
    cb(null, namaUnik);
  }
});

const upload = multer({ storage });

// Route upload satu file
app.post('/upload', upload.single('gambar'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'Tidak ada file yang diupload' });
  }

  res.json({
    pesan: 'Upload berhasil',
    file: {
      nama: req.file.filename,
      ukuran: req.file.size,
      tipe: req.file.mimetype,
      url: `/uploads/${req.file.filename}`
    }
  });
});

Pastikan folder uploads/ sudah ada, dan serve file statisnya:

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

Validasi Tipe File dan Ukuran

const fileFilter = (req, file, cb) => {
  const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];

  if (allowedTypes.includes(file.mimetype)) {
    cb(null, true);   // terima file
  } else {
    cb(new Error('Tipe file tidak didukung. Hanya JPG, PNG, WebP, GIF.'), false);
  }
};

const upload = multer({
  storage,
  fileFilter,
  limits: {
    fileSize: 5 * 1024 * 1024,  // maks 5MB
    files: 5                     // maks 5 file sekaligus
  }
});

Upload Multiple File

// Upload beberapa file dengan field name yang sama
app.post('/upload/multiple', upload.array('foto', 5), (req, res) => {
  if (!req.files || req.files.length === 0) {
    return res.status(400).json({ error: 'Tidak ada file' });
  }

  const files = req.files.map(f => ({
    nama: f.filename,
    ukuran: f.size,
    url: `/uploads/${f.filename}`
  }));

  res.json({ pesan: `${files.length} file berhasil diupload`, files });
});

// Upload dari beberapa field berbeda
app.post('/upload/mixed', upload.fields([
  { name: 'avatar', maxCount: 1 },
  { name: 'galeri', maxCount: 10 }
]), (req, res) => {
  const avatar = req.files['avatar']?.[0];
  const galeri = req.files['galeri'] || [];

  res.json({
    avatar: avatar ? `/uploads/${avatar.filename}` : null,
    galeri: galeri.map(f => `/uploads/${f.filename}`)
  });
});

Organisasi Folder Upload

Pisahkan file berdasarkan tipe atau tanggal agar mudah dikelola:

const fs = require('fs');

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    // Buat subfolder berdasarkan bulan/tahun
    const now = new Date();
    const folder = `uploads/${now.getFullYear()}/${String(now.getMonth() + 1).padStart(2, '0')}`;

    // Buat folder jika belum ada
    fs.mkdirSync(folder, { recursive: true });
    cb(null, folder);
  },
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname).toLowerCase();
    cb(null, `${Date.now()}${ext}`);
  }
});

Upload dengan Data Form Sekaligus

Upload file sering disertai data teks (judul, deskripsi, dll.):

app.post('/artikel', upload.single('thumbnail'), (req, res) => {
  // Data teks dari body
  const { judul, konten, kategori } = req.body;

  // File thumbnail
  const thumbnail = req.file ? `/uploads/${req.file.filename}` : null;

  if (!judul || !konten) {
    // Hapus file yang sudah terlanjur diupload jika validasi gagal
    if (req.file) fs.unlinkSync(req.file.path);
    return res.status(422).json({ error: 'Judul dan konten wajib diisi' });
  }

  const artikel = { id: Date.now(), judul, konten, kategori, thumbnail };
  res.status(201).json({ pesan: 'Artikel dibuat', data: artikel });
});

Menangani Error Multer

Error Multer tidak otomatis ditangani oleh error handler Express. Perlu penanganan khusus:

function uploadMiddleware(req, res, next) {
  upload.single('gambar')(req, res, (err) => {
    if (err instanceof multer.MulterError) {
      if (err.code === 'LIMIT_FILE_SIZE') {
        return res.status(400).json({ error: 'Ukuran file melebihi batas 5MB' });
      }
      if (err.code === 'LIMIT_FILE_COUNT') {
        return res.status(400).json({ error: 'Terlalu banyak file' });
      }
      return res.status(400).json({ error: err.message });
    } else if (err) {
      return res.status(400).json({ error: err.message });
    }
    next();
  });
}

app.post('/upload', uploadMiddleware, (req, res) => {
  res.json({ file: req.file });
});

Menyimpan ke Cloud (Cloudinary)

Untuk production, menyimpan file di server lokal kurang ideal. Integrasi dengan Cloudinary memungkinkan file tersimpan di CDN cloud:

npm install cloudinary multer-storage-cloudinary
const cloudinary = require('cloudinary').v2;
const { CloudinaryStorage } = require('multer-storage-cloudinary');

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

const cloudStorage = new CloudinaryStorage({
  cloudinary,
  params: {
    folder: 'blog-uploads',
    allowed_formats: ['jpg', 'png', 'webp'],
    transformation: [{ width: 1200, crop: 'limit', quality: 'auto' }]
  }
});

const uploadCloud = multer({ storage: cloudStorage });

app.post('/upload/cloud', uploadCloud.single('gambar'), (req, res) => {
  res.json({ url: req.file.path });
});

Kesimpulan

Multer membuat upload file di Express menjadi mudah dan fleksibel. Mulai dari penyimpanan lokal dengan nama file unik, validasi tipe dan ukuran, hingga integrasi cloud storage — semua bisa dikonfigurasi dengan bersih.

Di artikel terakhir seri ini, kita bahas cara deploy Express.js ke production dengan PM2 dan environment variables yang aman.

Kiki/🎮🍉⌨️🍩💻
Written by Kiki/🎮🍉⌨️🍩💻
hello I'm friend K.