DEV Community

Cover image for Handling File Uploads in Express with Multer
Shivam Yadav
Shivam Yadav

Posted on

Handling File Uploads in Express with Multer

yooo its me

the writter of this blog

today blog is all about multer yes that module which is kinda having 3 or 4 million download a week yes it has

so let see what i am going to cover in this blog

1) how file transfer from frontend to backend
2) what is multer
3) how to use multer
4) kinda eveyrthing about multer and how to use it


first let biginner

1) how file travels from frontend to backend

Normal HTTP requests usually send text like this

{
  "name": "shivam"
}
Enter fullscreen mode Exit fullscreen mode

which is done by express by adding things like

app.use(express.json());
Enter fullscreen mode Exit fullscreen mode

and

app.use(express.urlencoded());
Enter fullscreen mode Exit fullscreen mode

for text-based data.

This is easy.

But files are NOT text.

A PNG file is raw binary bytes:

89 50 4E 47 ...
Enter fullscreen mode Exit fullscreen mode

So browsers needed a special way to send everything in proper way:

  • text
  • files
  • metadata

all together in ONE request.

and that will be done using:

multipart/form-data

why called multipart?

because it contain multi form data 😭

yes this is why it is called like that


Now Let’s Break This Down

Part 1

------WebKit123
Content-Disposition: form-data; name="username"

shivam
Enter fullscreen mode Exit fullscreen mode

This means:

{
  username: "shivam"
}
Enter fullscreen mode Exit fullscreen mode

Part 2 (File)

------WebKit123
Content-Disposition: form-data; name="image"; filename="cat.png"
Content-Type: image/png
Enter fullscreen mode Exit fullscreen mode

This is metadata.

It tells:

  • field name = image
  • filename = cat.png
  • mime type = image/png

Then comes:

(binary bytes)
Enter fullscreen mode Exit fullscreen mode

Actual file data.


How Data Actually Travels

HTTP body travels as STREAMS

NOT like a giant packet.

Instead:

Chunk 1
Chunk 2
Chunk 3
Chunk 4
Enter fullscreen mode Exit fullscreen mode

Like:

------WebKit123
Content-Dispo
Enter fullscreen mode Exit fullscreen mode

then:

sition: form-data;
Enter fullscreen mode Exit fullscreen mode

then:

name="image"
Enter fullscreen mode Exit fullscreen mode

Everything arrives gradually.


Node.js Receives It as Stream

Inside Node.js req is actually a readable stream.

You can literally do:

req.on("data", chunk => {
   console.log(chunk);
});
Enter fullscreen mode Exit fullscreen mode

Example you may see:

<Buffer 2d 2d 2d 2d 57 65 62 4b>
Enter fullscreen mode Exit fullscreen mode

These are raw bytes.


now the best part comes

how a developer should handle this

see express is not having anything inbuilt to handle this

but there is one module:

multer

it helps us convert that raw bit into proper data

kinda like this:

{
  fieldname: 'image',
  originalname: 'cat.png',
  encoding: '7bit',
  mimetype: 'image/png',
  destination: 'uploads/',
  filename: 'a8f91c.png',
  path: 'uploads/a8f91c.png',
  size: 34567
}
Enter fullscreen mode Exit fullscreen mode

let see how multer does that

Multer acts as Middleware between request and route handler.

multer parse this stream manually like:

  • Reads chunks
  • Detects boundaries
  • Separates parts
  • Reads headers
  • Extracts metadata
  • Writes file bytes to disk

How File Is Recreated

Suppose multer extracts:

89 50 4E 47 ...
Enter fullscreen mode Exit fullscreen mode

(this data is after cleaning all the other data this is only the file data)

These are PNG bytes.

It simply writes them into a file using:

  • fs.writeFile()
  • or stream pipe

Because files ARE just bytes.

yes it is that simple 😭


SUPER IMPORTANT UNDERSTANDING

A file is NOT special.

A file is just:

Raw bytes + metadata
Enter fullscreen mode Exit fullscreen mode

Example:

cat.png

is just:

[bytes] stored on disk
Enter fullscreen mode Exit fullscreen mode

now this is how you implment multer code

first : Install Multer

npm install multer
Enter fullscreen mode Exit fullscreen mode

Step 2: Basic Express Setup

like Create a server.js file and write this code inside it

Code:

const express = require("express");
const multer = require("multer");

const app = express();

app.listen(3000, () => {
  console.log("Server running");
});
Enter fullscreen mode Exit fullscreen mode

Step 3: Create Uploads Folder

Inside project create a /uploads folder (basically here we are going to save the data)

project/
β”‚
β”œβ”€β”€ uploads/
β”œβ”€β”€ server.js
└── package.json
Enter fullscreen mode Exit fullscreen mode

inshort: This (/uploads) folder stores uploaded files.


Step 4: Basic Multer Setup

as u can sence the multer is a function and we are destcting it and giving the dest paramter a value

const upload = multer({
  dest: "uploads/"
});
Enter fullscreen mode Exit fullscreen mode

this is Very basic configuration.

What dest Does ?

it just say store data inside uploads

dest: "uploads/"
Enter fullscreen mode Exit fullscreen mode

means:

"Store uploaded files inside uploads folder"


Step 5: Single File Upload

app.post("/upload", upload.single("image"), (req, res) => {
  res.send("File uploaded");
});
Enter fullscreen mode Exit fullscreen mode

first Understanding upload.single()

upload.single("image")
Enter fullscreen mode Exit fullscreen mode

it means:

  • Accept only one file from frontend
  • frontend Input field name must be "image"

this is how Frontend HTML Form look likes

<form action="/upload" method="POST" enctype="multipart/form-data">

  <input type="file" name="image" />

  <button type="submit">
    Upload
  </button>

</form>
Enter fullscreen mode Exit fullscreen mode

Important thing to notice:

enctype

This is very critical

enctype="multipart/form-data"
Enter fullscreen mode Exit fullscreen mode

Without this File upload fails.

after all this thing Uploaded file appears inside uploads/

Example:

8f3a12d8a91b2c.png
Enter fullscreen mode Exit fullscreen mode

Multer auto-generates random names by default.


this is how you Access Uploaded File Info

After upload req.file contains file metadata.

Example:

console.log(req.file);
Enter fullscreen mode Exit fullscreen mode

Example req.file Object

{
  fieldname: 'image',
  originalname: 'photo.png',
  encoding: '7bit',
  mimetype: 'image/png',
  destination: 'uploads/',
  filename: 'a83b12d81.png',
  path: 'uploads/a83b12d81.png',
  size: 12000
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Custom Storage Configuration

Basic dest works

But usually developers need:

  • Custom names
  • Better folder control

Use:

diskStorage()
Enter fullscreen mode Exit fullscreen mode

Custom Storage Setup

const storage = multer.diskStorage({

  destination: function (req, file, cb) {
    cb(null, "uploads/");
  },

  filename: function (req, file, cb) {
    cb(null, Date.now() + "-" + file.originalname);
  }

});
Enter fullscreen mode Exit fullscreen mode

first Understand destination()

destination(req, file, cb)
Enter fullscreen mode Exit fullscreen mode

its just work same as dest it define where the folder should be kept


second think to notice is Understanding filename()

filename(req, file, cb)
Enter fullscreen mode Exit fullscreen mode

so using this we can make your own custom file name

Use Date.now()

because Without unique naming:

image.png
image.png
image.png
Enter fullscreen mode Exit fullscreen mode

Files might overwrite each other.

Using Date.now() prevents collisions.


Connect Storage to Multer

const upload = multer({
  storage: storage
});
Enter fullscreen mode Exit fullscreen mode

Complete Single Upload Example

const express = require("express");
const multer = require("multer");

const app = express();

const storage = multer.diskStorage({

  destination: function (req, file, cb) {
    cb(null, "uploads/");
  },

  filename: function (req, file, cb) {
    cb(null, Date.now() + "-" + file.originalname);
  }

});

const upload = multer({ storage });

app.post("/upload", upload.single("image"), (req, res) => {

  console.log(req.file);

  res.send("Upload successful");

});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Multiple File Uploads

Sometimes users upload multiple files.

Example:

  • Product gallery
  • Multiple PDFs
  • Photo collections

Use upload.array() it basically help to take multiple file from frontend

Example

app.post("/uploads", upload.array("images", 5), (req, res) => {

  console.log(req.files);

  res.send("Files uploaded");

});
Enter fullscreen mode Exit fullscreen mode
upload.array("images", 5)
Enter fullscreen mode Exit fullscreen mode

basically means:

  • Field name = "images"
  • Maximum 5 files

Frontend will handle it like this

<input type="file" name="images" multiple />
Enter fullscreen mode Exit fullscreen mode

for accessing Single upload we can use req.file

but for Multiple uploads we can use req.files

because files become an array


3) Uploading Different Fields

so now comes when the user upload data from diff types like JPG , PNG , pdf ,etc so to handle that we can use upload.fields()

Example

app.post("/profile", upload.fields([
  { name: "avatar", maxCount: 1 },
  { name: "resume", maxCount: 1 }
]), (req, res) => {

  console.log(req.files);

  res.send("Uploaded");

});
Enter fullscreen mode Exit fullscreen mode

this is how u can access it

req.files.avatar
req.files.resume
Enter fullscreen mode Exit fullscreen mode

File Validation

Very important.

now there are some precaution u can take like Never trust uploads blindly.

1) Restrict File Types

in this only certain file type are allowed to be entered into the server

this is how u can implement that

const fileFilter = (req, file, cb) => {

  if (file.mimetype.startsWith("image")) {
    cb(null, true);
  }

  else {
    cb(new Error("Only images allowed"));
  }

};
Enter fullscreen mode Exit fullscreen mode

Connect Filter

const upload = multer({
  storage,
  fileFilter
});
Enter fullscreen mode Exit fullscreen mode

File Size Limits

2) Prevent huge uploads.

see the stoarage has a limit and if user uplaod data which is in high amount there is a huge possiblity that stoarage limit will get hit so to restrict that we can use limits

like this

const upload = multer({
  storage,

  limits: {
    fileSize: 5 * 1024 * 1024
  }

});
Enter fullscreen mode Exit fullscreen mode

5MB limit


3) Serving Uploaded Files

Uploading alone is not enough

Browser must access files too then we can use the express.static() function

any folder name passed inside static the data inside that folder will be accessable to the user

app.use("/uploads", express.static("uploads"));
Enter fullscreen mode Exit fullscreen mode

Access File via URL

Suppose file:

uploads/photo.png
Enter fullscreen mode Exit fullscreen mode

URL:

http://localhost:3000/uploads/photo.png
Enter fullscreen mode Exit fullscreen mode

Now browser can open uploaded image.


Folder Structure

project/
β”‚
β”œβ”€β”€ uploads/
β”‚   β”œβ”€β”€ image1.png
β”‚   β”œβ”€β”€ image2.jpg
β”‚
β”œβ”€β”€ server.js
└── package.json
Enter fullscreen mode Exit fullscreen mode

Common Multer Methods

Method Purpose
single() One file
array() Multiple files
fields() Multiple named fields
none() Only text fields
any() Accept all files

What is upload.any() ?

upload.any() accepts every uploaded file.

really Not recommended for beginners like there will be so many issue u cannot imagine stik to the traditional part


Common Beginner Mistakes

1. Forgetting uploads Folder

Multer cannot save files without giving a proper place to store it


2. Wrong Field Name

Frontend:

name="photo"
Enter fullscreen mode Exit fullscreen mode

Backend:

upload.single("image")
Enter fullscreen mode Exit fullscreen mode

Upload will fails.

Names must match.


3. Missing enctype

( ooh i have done this so many times)

Without multipart/form-data file upload breaks.

rember this properly


4. Forgetting express.static()

Files upload successfully but URLs fail.


5. Using Original Filenames

( atleast use Date.now()) dont be lazy


Upload Flow Diagram

User Selects File
        ↓
Browser Sends multipart/form-data
        ↓
Multer Middleware Executes
        ↓
File Saved in uploads/
        ↓
req.file Created
        ↓
Route Handler Executes
        ↓
Response Sent Back
Enter fullscreen mode Exit fullscreen mode

Final Understanding

Multer is middleware that helps Express handle:

multipart/form-data
Enter fullscreen mode Exit fullscreen mode

It processes uploaded files, stores them, and makes file metadata available inside request objects.

so this is the end of the blog if u liked the blog with comment it down and if there is something bad just let me know

and also like the blog follow for more such blog

bye bye

Top comments (0)