Engineering Behind Uploading a File
"Click."
That's all we do.
We press an Upload button, select a file, wait a few seconds, and it's done.
Simple.
But underneath that tiny click, millions of tiny events happen before your photo finally reaches a server.
Let's follow a single file on its journey.
It All Starts With a Click
Imagine you're uploading a 2 GB video.
You click Upload.
The browser doesn't magically send the entire file at once.
Instead, it opens the file and starts reading it piece by piece.
Think of reading a 500-page book.
You wouldn't try to memorize every page before speaking.
You'd read a few pages...
Talk...
Read a few more...
And continue.
Uploading a file works exactly the same way.
Your File
───────────────
████████████████████████
↓
Read Small Piece
↓
Send
↓
Read Next Piece
↓
Send
↓
Repeat...
Why Not Send Everything Together?
Because computers also have limits.
Imagine trying to pour an entire swimming pool through a garden hose.
Impossible.
The pipe simply isn't big enough.
Computers have a similar limitation.
Memory isn't infinite.
Network speed isn't infinite.
The operating system cannot process unlimited data instantly.
So instead of sending everything together...
It sends small chunks.
These chunks are called buffers.
Buffers — The Temporary Waiting Room
A buffer is nothing more than a temporary waiting area.
Think about an airport security line.
Passengers don't immediately enter the airplane.
They first wait in a queue.
Only when space becomes available do they move forward.
A computer does exactly the same.
Large File
██████████████████████
↓
Buffer
████
↓
Network
↓
Server
Instead of pushing 2 GB at once,
the browser keeps filling small buffers and sending them one after another.
This keeps memory usage small and predictable.
The Network Doesn't Always Move at Your Speed
Now imagine your internet suddenly becomes slow.
Your browser is still reading the file.
But the network is taking longer to send each chunk.
If the browser keeps reading at full speed...
Eventually memory fills up.
Everything slows down.
Or worse—
The application crashes.
So how does Node.js avoid this?
Streams
Instead of treating a file as one giant object,
Node treats it like flowing water.
Water doesn't arrive all at once.
It flows continuously.
A file behaves the same way.
Node reads...
Sends...
Reads...
Sends...
Continuously.
That's what a stream is.
File
████████████████████
↓
Readable Stream
~~~~~~~~~~~~~~
↓
Network
~~~~~~~~~~~~~~
↓
Writable Stream
↓
Disk
Streams allow applications to process files that are much larger than available memory.
Even a 20 GB file can be uploaded without ever storing the whole thing in RAM.
But Who Decides When To Read More?
Imagine you're filling bottles from a tap.
If the bottles are being packed quickly,
you keep pouring.
If packing becomes slow,
you stop pouring for a moment.
Otherwise...
Water spills everywhere.
Node follows the same idea.
This is called Backpressure.
Fast Reader
████████
↓
Slow Network
██
↓
STOP
↓
Wait
↓
Continue
Instead of flooding memory,
Node simply pauses reading until the receiver catches up.
This tiny mechanism is responsible for making uploads stable.
Without it,
large uploads would quickly consume memory and crash applications.
Where Does the Data Go Next?
So far we've only seen JavaScript.
But JavaScript isn't talking directly to your network card.
There are many layers underneath.
The journey looks something like this.
Browser
↓
Network
↓
Operating System
↓
Node.js
↓
Readable Stream
↓
Buffer
↓
Writable Stream
↓
Disk
Every chunk of your file travels through these layers.
Each one has a small responsibility.
Together,
they move billions of bytes every day.
The Operating System Is Doing Most of the Heavy Lifting
One surprising thing I learned was this:
Node.js isn't manually copying every byte around.
The operating system is incredibly good at moving data.
Node mostly coordinates the process.
The operating system receives network packets,
stores them temporarily,
notifies Node that new data has arrived,
and Node continues processing it.
This separation allows Node to handle thousands of uploads simultaneously without creating thousands of threads.
So What Actually Happens?
When you upload a file,
this is roughly what happens.
Click Upload
↓
Browser opens the file
↓
Reads a small chunk
↓
Places it into a buffer
↓
Sends it over the network
↓
Operating System receives it
↓
Node.js is notified
↓
Readable Stream receives the bytes
↓
Backpressure checks if it's safe
↓
Writable Stream writes to disk
↓
Repeat until complete
Nothing magical.
Just millions of tiny pieces moving one after another.
Why This Changed How I Think About Backend Engineering
Before learning how uploads worked,
I imagined that a file somehow "appeared" inside my Express route.
Now I see something completely different.
I see flowing data.
Temporary waiting areas.
Small chunks moving through buffers.
Streams that pause and resume.
An operating system quietly coordinating everything underneath.
Uploading a file isn't about calling an API.
It's about moving bytes safely from one machine to another.
Once I understood that, streams, buffers, and backpressure stopped feeling like abstract concepts—they became natural solutions to a very practical problem.
Final Thought
Every time you click Upload, remember this:
Your computer doesn't send a file.
It sends millions of tiny bytes, patiently, one chunk at a time, while the browser, operating system, network, and Node.js work together to ensure that not a single byte gets lost along the way.