From SYN to res.end() — The Complete Anatomy of a Node.js Upload Request
When you click “Upload” in a browser, what actually happens inside a Node.js server?
From SYN to res.end() — The Complete Anatomy of a Node.js Upload Request
When you click “Upload” in a browser, what actually happens inside a Node.js server?
Not the simplified version. Not “it goes to Express.” The real version.
Before your JavaScript callback ever runs, there is a TCP handshake at the operating system level, raw binary packets flowing into kernel memory, a high-performance C++ HTTP parser scanning for \r\n\r\n, and a carefully orchestrated handoff between Libuv, V8, and worker threads — all before a single byte touches your disk.
In this article, we’ll trace the exact chronological journey of a 5GB file upload — from SYN packet to res.end() — and uncover how Node.js moves data without ever loading the entire file into memory.
title Crisis Response Event-Driven Architecture
Let’s trace the absolute chronological journey of a single request — from the exact millisecond the user presses “Upload” in their browser, all the way to the file resting safely on your server’s hard drive.
We will connect the TCP Handshake, the C++ Parser, and the JavaScript Streams into one continuous timeline.

clean “Upload Request” End-to-End Sequence Diagram
Phase 1: Establishing the physical “Pipe” (The TCP Handshake)
Before any data about your file or website is sent, the two computers must agree to talk.
- The Knock: The client’s browser finds your server’s IP address and knocks on your specific Port (e.g., Port 3000).
- The Handshake: The client and your server’s Operating System (OS) perform the 3-Way TCP Handshake (SYN, SYN-ACK, ACK).
- The Socket: Once the handshake is complete, a physical TCP Socket is established. Think of this as a secure, open pipe between the client’s house and your server room. At this exact moment, Node.js (via the
netmodule and Libuv) is notified: "A pipe is now open."

3 way Handshake
Phase 2: The Data Begins to Flow (Raw Binary)
Now that the pipe is open, the client starts pushing the 5GB video file into the pipe.
- The Breakdown: The client’s computer doesn’t send a “file.” It chops the video into microscopic electronic packets (raw binary data) and fires them through the internet.
- The OS Buffer: These packets arrive at your server’s Network Card. Your Operating System catches them and places them into a small, temporary waiting room in the OS memory called the Socket Buffer.
- Libuv Steps In: Libuv (Node’s C++ engine) is constantly monitoring this OS buffer. As soon as binary data lands there, Libuv grabs it and pulls it into Node.js.
Phase 3: The C++ Interception (The Parser)
Libuv now holds a chunk of raw binary data. But JavaScript isn’t allowed to see it yet.
- The Inspection: Libuv hands the raw data to the
**llhttpC++ Parser** (the high-speed robot we discussed earlier). - Reading the Metadata: The parser scans the very first few bytes of the data. It is looking for the HTTP Headers. It reads things like:
POST /upload HTTP/1.1Content-Type: video/mp4Content-Length: 5000000000(5GB)
The Boundary: The C++ parser looks for a specific hidden character: \r\n\r\n (two blank lines). In the HTTP protocol, this character means: "The headers are finished. Everything after this line is the actual file (the Body)."
Phase 4: The JavaScript Handoff (The req Object)
Once the C++ parser finds that boundary, it stops reading. It does not read the 5GB body.
- Object Creation: The
httpmodule takes the parsed headers and constructs the JavaScriptreqobject (IncomingMessage). - The Pause: Node.js intentionally pauses the flow of data coming from the pipe. It holds the
reqobject and triggers your Express orhttpcallback:(req, res) => { ... }. - The Choice: At this moment, the 5GB file is paused, waiting inside the OS network buffer. Node.js is waiting for you (the developer) to tell it what to do with the body.
Phase 5: Consuming the Stream (The .pipe() Action)
Inside your callback, you write the magic line: req.pipe(writeStream). This tells Node.js to unpause the flow and manage the memory.
- Unpausing the Flow: The
reqobject (a Readable Stream) tells Libuv to start pulling the rest of the 5GB binary data from the OS buffer. - Chunking: The data is pulled in small pieces (Chunks), usually 64KB at a time.
- The Transfer: * Chunk 1 arrives in RAM.
.pipe()immediately pushes Chunk 1 to the Writable Stream (fs).- The Writable Stream uses a background C++ Worker Thread to physically write Chunk 1 to the hard drive.
- Once Chunk 1 is safely on the disk, it is erased from RAM.
Backpressure Management: If the hard drive takes too long to write Chunk 1, .pipe() tells Libuv: "Tell the OS to tell the client to stop sending packets for a millisecond." This prevents the OS buffer and the RAM from overflowing.
Phase 6: The Teardown (Response and Disconnect)
Finally, after millions of chunks have been routed from the network card, through the RAM, and onto the disk, the client sends a final “End of File” signal.
- The End Event: The C++ parser sees the end of the data. The
reqstream emits the'end'event. - The Response: Your code runs
res.end('Upload Complete'). Theresobject (a Writable Stream) formats this string into an HTTP-compliant binary packet and sends it back down the TCP pipe to the client. - The Cleanup: Depending on the
Connection: keep-aliveheader, the OS will either tear down the TCP socket (closing the pipe) or keep it open for the client's next request. The memory used for thereqandresobjects is swept away by the V8 Garbage Collector.
This is the true, end-to-end anatomy of a request. It is a highly coordinated dance between the Operating System’s network layer, high-speed C++ parsers, and JavaScript memory management.
메타데이터
- post_id
- f1ea03ddb495
- slug
- from-syn-to-res-end-the-complete-anatomy-of-a-node-js-upload-request-f1ea03ddb495
- url
- https://javascript.plainenglish.io/from-syn-to-res-end-the-complete-anatomy-of-a-node-js-upload-request-f1ea03ddb495
- canonical_url
- https://javascript.plainenglish.io/from-syn-to-res-end-the-complete-anatomy-of-a-node-js-upload-request-f1ea03ddb495
- author_url
- https://medium.com/@anoop9569110314
- status
- ok
- fetched_at
- 2026-06-24 04:09:36