Skip to main content

Command Palette

Search for a command to run...

Handling File Uploads in Express with Multer

Updated
6 min read
Handling File Uploads in Express with Multer

The first time I tried handling file uploads in Express…

I thought it would work like normal form data.

Send request.

Read req.body.

Done.

Simple.

But then I tried uploading a file…

and nothing made sense.

The file wasn’t where I expected.

req.body didn’t behave the way I thought.

And I remember thinking…

Why is uploading a file different from sending normal text fields?

That was my first encounter with why file uploads need special handling.

And honestly…

that confusion led me to Multer.


Why File Uploads Need Middleware

This clicked when I realized:

A file is not like a regular text value.

Sending:

name=Sahil

is one thing.

Sending an image…

very different.

There is more data.

Different structure.

Different processing.

And Express doesn’t magically handle all of that by itself.

That’s where middleware comes in.


The Word That Confused Me

multipart/form-data

This sounded scary the first time I saw it.

It really didn’t need to.

Simple beginner understanding:

It’s a format browsers use when sending files.

That’s enough.

I didn’t need deeper protocol details to understand uploads.

And honestly…

that was enough to move forward.


I Think Of It Like Sending A Package

This analogy helped me.

Normal form field:

Like sending a note.

Very simple.

File upload:

Like sending a package.

Needs different handling.

That made it click.


Client → Server → Storage Flow


What Multer Is

Simple version:

Multer is Express middleware for handling file uploads.

That’s it.

It sits in the request flow…

helps process incoming files…

and makes them available to your code.

That’s how I understood it.

And that was enough.


First Time I Used It

Install:

npm install multer

Then:

const multer =
require("multer");

That was my starting point.


Single File Upload

This was the first thing that made sense.

const upload = multer({

 dest:"uploads/"

});

Then:

app.post(

"/upload",

upload.single(
"photo"
),

(req,res)=>{

 res.send(
 "Uploaded"
 );

}

);

And I remember thinking…

wait…

that’s cleaner than I expected.


What single("photo") Means

This confused me initially.

It refers to the field name.

Like:

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

That name:

photo

matches:

upload.single("photo")

Once I saw that…

it clicked.


Multer Middleware Flow


Accessing Uploaded File

This was cool.

Multer puts file info on:

req.file

Example:

console.log(
req.file
);

And suddenly I could actually see uploaded file data.

That felt satisfying.


Multiple File Uploads

Then I learned:

It isn’t just single files.

You can do multiple too.

app.post(

"/photos",

upload.array(
"images",
3
),

(req,res)=>{

 res.send(
 "Files uploaded"
 );

}

);

Now:

req.files

instead of:

req.file

That was a nice distinction.


That Was My “Ohhh” Moment

Single file:

req.file

Multiple:

req.files

Simple.

But important.

That helped me remember it.


Storage Configuration Basics

At first I used:

dest:"uploads/"

Very simple.

And honestly…

good enough to start.

Later I learned you can customize storage.

Like filename control.

Destination control.

Example:

const storage =
multer.diskStorage({

 destination:

 function(

 req,file,cb

 ){

  cb(
   null,
   "uploads/"
  );

 },

 filename:

 function(

 req,file,cb

 ){

  cb(
   null,
   file.originalname
  );

 }

});

Then:

const upload=
multer({

 storage

});

That looked intimidating at first.

But conceptually…

it is just saying:

Where to save.

How to name.

That’s all.


Serving Uploaded Files

This part was new to me.

Uploading is one thing.

Serving uploaded files back is another.

Simple Express setup:

app.use(

"/uploads",

express.static(
"uploads"
)

);

That makes uploaded files accessible.

And when I first saw that…

it connected the whole flow for me.

Upload.

Store.

Serve.

Complete cycle.


Upload Lifecycle In My Head

User selects file.

Browser sends file.

Multer processes it.

Server stores it.

App can access it.

That mental sequence helped me.

A lot.


One Mistake I Made

I thought file would appear in:

req.body

Wrong.

That confused me early.

File data comes through Multer handling.

Different path.

Important distinction.


Another Thing I Got Wrong

I assumed Multer stores in cloud.

No.

Multer handles upload processing.

Storage decisions are separate.

I mixed those together initially.

Worth saying.


Tiny Practice Example

Start with one file:

upload.single(
"avatar"
)

Then try:

console.log(
req.file
);

Seeing that object teaches a lot.

Honestly.


Why Middleware Made More Sense Here

Before this…

middleware felt abstract.

With Multer…

I saw middleware doing real work.

Request comes in.

Middleware processes file.

Route gets clean access.

That made middleware click even more.


What Finally Made It Click

I stopped thinking:

File upload is just another form field.

And started thinking:

It needs its own processing pipeline.

That made everything make sense.

And that is why Multer exists.


Quick Recap

  • File uploads need middleware

  • Multer handles upload processing

  • single() for one file

  • array() for multiple files

  • Storage can be configured

  • Uploaded files can be served back

That’s the foundation.


Conclusion

The first time I tried file uploads…

I expected it to work like normal form data.

It didn’t.

And that confusion is what led me to understand Multer.

Now it feels much simpler.

Request comes in.

Multer processes file.

Server stores it.

Route handles result.

That’s the core.

If you remember one thing from this article, remember this:

File uploads need special request processing…
and that is exactly where Multer helps.

That idea made it click for me.

If you like this simple learning-style explanation,
I write more notes at
devwithsahil.hashnode.dev
and share progress on LinkedIn 🙂