What Makes Buffers,Streams and Files Different?
Ever wondered why developers use buffers instead of files—or vice versa? This post explains the core difference between them and when to use each in real-world coding.
"Data doesn't just sit there—it flows. From your keyboard to your screen, from memory to disk, from one program to another. Understanding this flow is the key to understanding the whys, hows, whats etc.
It all starts with buffers: the temporary rest stops in your data's journey. Your file exists in three different states simultaneously namely : the past (what's on disk), the present (what's in your buffer), and the future (what's flowing through streams).We barely even realize this happen just within our precious machines."
What you'll learn
- What a buffer is and how it works under the hood.
- How files are stored and retrieved from disk.
- How to convert between a file and a buffer in Node.js.
- Why and When youtube Api uses streams and buffers interchangeably.
Prerequisite
This guide assumes you have some interest in tech and looking forward to having a deeper understanding of what actually happens under the hood ...
Basic understanding of NodeJs
Try Kodaschool for free
Click below to sign up and get access to free web, android and iOs challenges.
Real-Life Analogy
Think of a buffer as a holding zone e.g when u want to transfer water to a bottle from a jerrican you first transfer it to a jug then u can now transfer it to a bottle with minimal loss.
Have you ever wondered what are these table like numbers in the browser's "Network Requests Tab"

Think of a stream as a conveyor belt - data moves continuously in one direction, piece by piece. You can't stop the belt to rearrange items, you can't go backwards to grab something you missed, and you process each item as it comes.
Think of a file as a storage container in your garage - it sits there permanently, you can access it whenever you want, rearrange its contents(spanner,spark plug), add or remove things, and it stays exactly as you left it until you decide to change it again.
Introduction
Well then the big question is whats actually:
- Buffer - Buffer is a container for raw bytes where a byte contains 8 bits (0's and 1's) so you maybe familiar with this number 00110101 or 0x000000.
- Anytime your program wants to communicate with outside itself, it needs to work through bytes, that’s what every single language understand, that’s what every single language is build on top.
- A buffer in a computer is a storage space set aside to hold data before it gets processed.
- A buffer is anything that is loaded into the memory which is going to be used in the immediate future.
- With tools like Vim, it means any file that you have opened in Vim that is stored in the memory for editing.
- File - A file is a collection of data that is stored permanently on your disk (hard drive, SSD, etc.)
- Examples include :document.txt, image.png all of this just sit on your disk waiting to be accessed
- Files persist even when your computer is turned off - they're your permanent storageA file has a name, location, and contains data that doesn't change unless you explicitly modify it
- Stream - A stream is a sequence of data that flows continuously from one point to another.Its like data either coming in (stdin), going out (stdout)
- Unlike buffers and files, streams are all about movement - data is always flowing, never static. You can only read a stream in one direction (forward) and you can't go back to re-read previous data
- Data in a stream is processed piece by piece as it arrives, not all at once
- lets have a look at this two cli commands:
sed
– Stream Editor (s in sed stands for stream)
It reads text line by line from a stream, applies transformations (like find-and-replace), and writes to another stream.
echo "hello world" | sed 's/world/Barack/'
# Output: hello Barack
awk
– Pattern Scanning & Processing
It scans and processes fields (columns) based on patterns.It doesn't read the entire file at once but just streams through it line-by-line.
echo "John 23" | awk '{print $1}'
# Output: John
1.What is a buffer and how does it work under the hood?
At its core, a buffer is just a chunk of memory that holds raw bytes.Think of it like reserving a parking lot with numbered spaces - each space can hold one byte (8 bits), and you know exactly where each piece of data sits.

Reality of Unbuffered Operations
Imagine you're writing data to a file character by character without any buffering "practice of preloading and storing a portion of a media file in the buffer or temporary memory of a device that enable media playback without jitter or stuttering"
Every single character you write triggers a system call to the operating system:
Lets asume we wanna write the word "hello"
writeToFile('H'); // System call #1
writeToFile('e'); // ...#2
writeToFile('l'); // ... #3
writeToFile('l'); // ... #4
writeToFile('o'); // ... #5
sys calls are really expensive since it requires switching from user mode to kernel mode, updating file metadata, moving disk heads, and switching back
Buffers Magic
buffer.write('H');
buffer.write('e');
buffer.write('l');
buffer.write('l');
buffer.write('o');
buffer.flush();
Instead of the 5 system calls, you make just 1. The buffer acts like a shopping cart - you collect all your items (data) first, then make one trip to the checkout (disk write).
The Three Types of Buffering
1. Fully Buffered (Block Buffering)
- Data is written to disk only when the buffer is full msot efficient for throughput.
- Buffer size typically 4KB or 8KB
2. Line Buffered
- Data is written when a newline character is encountered mainly used for terminal output.
- Balances efficiency with real-time feedback
3. Unbuffered
- Data is written immediately and mainly used for error streams where you need immediate output
- Slower but more predictable timing
Memory Layout: How Buffers Actually Store Data
When you create a buffer in Node.js with Buffer.alloc(10)
, you're telling the system "give me 10 consecutive memory slots." These slots are filled with zeros initially, like empty parking spaces waiting for cars.
The magic happens in how buffers handle different data types. When you write the string "hello" to a buffer, it doesn't store the word "hello" - it stores the numeric values that represent each letter in a specific encoding (usually UTF-8). The letter 'h' becomes the number 72, 'e' becomes 101, and so on.
Memory Address: 0x1000 0x1001 0x1002 0x1003 0x1004
Buffer Content: 72 101 108 108 111
ASCII Letters: 'H' 'e' 'l' 'l' 'o'
Example
Each memory address holds exactly one byte. The buffer maintains two crucial pointers:
Write pointer: Where the next byte will be written
Read pointer: Where the next byte will be read from
Lets go through this example:
class Buffer {
constructor(size) {
this.data = new Uint8Array(size); // Raw byte storage
this.writePos = 0; // Current write position
this.readPos = 0; // Current read position
this.size = size; // Total buffer capacity
this.bytesUsed = 0; // How much data is stored
}
}
Modern computers read memory most efficiently in chunks (usually 4 or 8 bytes at a time). Buffers are typically aligned to these boundaries to maximize performance. This is why you might see buffer sizes like 4096 bytes (4KB) - it's optimized for the underlying hardware.
Read more about bufferes here: and here.
2.How files are stored and retrieved from disk
While buffers exist in fast RAM, files are stored on much slower but permanent storage like SSDs or spinning hard drives.
The File System: Your Disk's GPS
When you save a file, your operating system doesn't just dump the data randomly onto the disk.
It maintains a file system, essentially a detailed map that tracks where every file is located, how big it is, when it was created, and what permissions it has.
in traditional hdds Reading a file The OS checks its file system map, finds the physical location on disk, moves the read/write head to that spot (on spinning drives), and transfers the data sector by sector into memory. This process is thousands of times slower than accessing data already in memory, which is why the buffer exists as a middle layer.
Here is a summary:
Path Resolution: OS follows the directory structure (/home/user/documents/file.txt
)
Metadata Lookup: Checks the file system table to find physical locations
Disk Positioning: On HDDs, moves the read/write head to the correct track
Sector Reading: Reads data sector by sector (usually 512 bytes or 4KB chunks)
Buffer Loading: Transfers data into a buffer in RAM
Error Checking: Verifies data integrity using checksums
3.How to convert between a file and a buffer in Node.js
Here is a little code snippet that we will have a look at:
Converting a file to a buffer
const fs = require('fs');
// Read entire file into a buffer
const buffer = fs.readFileSync('document.txt');
console.log(buffer); // <Buffer 48 65 6c 6c 6f 20 77 6f 72 6c 64>
// Convert buffer to readable string
const text = buffer.toString('utf8');
console.log(text); // "Hello world"
Converting a buffer to a file
const data = Buffer.from('Hello world', 'utf8');
fs.writeFileSync('output.txt', data);
lets use a more familiar example from the Real world API
const key = process.env.MPESA_CONSUMER_KEY || "DV.....X5"
const secret = process.env.MPESA_CONSUMER_SECRET || "54.....aS"
const auth = Buffer.from(${key}:${secret}).toString("base64");
The code Gets your M-Pesa consumer key and secret from environment variables.
This creates a string in the format: "DV.....X5:54.....aS"
The colon acts as a standard separator for Basic Auth Credentials
Step 1. Buffer Creation
Buffer.from(`${key}:${secret}`)
This converts the string into a buffer of raw bytes.
String: "DV.....X5:54.....aS"
Buffer: <Buffer 44 56 2e 2e 2e 2e 2e 58 35 3a 35 34 2e 2e 2e 2e 2e 61 53>
Step 2: Base64 Encoding
.toString("base64")
This converts the buffer to a base64 string, which might look like:"RFYuLi4uLlg1OjU0Li4uLi5hUw=="
Why This Transformation Happens
HTTP Basic Authentication requires credentials to be sent in this specific format:
Authorization: Basic <base64-encoded-credentials>
Why and When youtube Api uses streams and buffers interchangeably
YouTube Adresses a unique challenge: serving billions of hours of video content to users worldwide, with file sizes ranging from small clips to 8K movies several gigabytes large.
For small thumbnails and metadata: YouTube uses buffers. A 50KB thumbnail image can be quickly loaded into memory, processed, and served to users without worrying about memory usage.
For video playback: YouTube uses streams. When you watch a video, you're not downloading the entire file - you're receiving a continuous stream of video chunks. This allows playback to start immediately while the rest downloads in the background.
For video uploads: YouTube combines both approaches. When you upload a video, it initially buffers smaller chunks for processing (compression, thumbnail generation), but streams the larger video data to avoid overwhelming their servers' memory.
For live streaming: YouTube relies heavily on streams since the content is being created in real-time. There's no complete "file" to buffer - just a continuous flow of video data that needs to be processed and distributed immediately.
This hybrid approach allows YouTube to cater for different scenarios:
- speed (buffers),
- memory efficiency (streams),
- permanent storage (files),
Try out and play with the YouTube Data API here
Here is a code snipeet of how you would implement the api
if (!file) {
return ResponseUtil.error(res, HttpStatus.BAD_REQUEST, 'Video file is required');
}
this.youtubeService.validateVideoFile(file);
const videoStream = bufferToStream(file.buffer);
// Upload the video
const result = await this.youtubeService.uploadVideo(
userId,
videoStream,
createVideoDto.title,
createVideoDto.description,
createVideoDto.privacyStatus,
createVideoDto.tags,
);
Hope you this post was Helpful
!! Happy Coding :-)