How Does the fs Module Work in Node.js?
Learn how the Node.js fs module reads, writes, and streams files, and why async methods keep your server fast. Clear examples and interview tips inside.
Expected Interview Answer
The fs module is Node.js's built-in file system library that lets you read, write, update, delete, and watch files and directories on disk, exposing each operation in synchronous, callback, and promise-based forms.
You load it with require('fs') or require('fs/promises'). Asynchronous methods like fs.readFile run the actual disk work on libuv's thread pool and hand the result back via a callback or a resolved promise, keeping the event loop free. Synchronous variants such as fs.readFileSync block the whole process until they finish, so they are reserved for startup scripts, not request handlers. The module also offers streams (createReadStream) for large files so you never load an entire file into memory at once.
- Built into Node.js — no npm install needed
- Non-blocking async APIs keep the event loop responsive
- Promise-based fs/promises works cleanly with async/await
- Streams handle large files with low memory use
- Covers files, directories, permissions, and file watching
AI Mentor Explanation
Think of the fs module as the scorer's desk beside the pitch. Reading a file is like fetching a past scorecard from the archive, writing is recording the latest over, and appending is adding one more ball to the sheet. The async version sends a runner to the archive room so play never stops, while the sync version freezes the whole match until the runner returns with the book.
Step-by-Step Explanation
Step 1
Import the module
Use require('fs') for classic APIs or require('fs/promises') for the promise-based versions that pair with async/await.
Step 2
Choose sync, callback, or promise
Pick async (readFile/promises) for servers so the event loop stays free; reserve sync methods for one-off startup scripts.
Step 3
Perform the operation
Call readFile, writeFile, appendFile, unlink, mkdir, or readdir with a path and, for text, an encoding like 'utf8'.
Step 4
Handle results and errors
Await the promise inside try/catch, or check the error argument in the callback before using the data.
Step 5
Use streams for large files
Switch to createReadStream/createWriteStream so big files flow in chunks instead of loading fully into memory.
What Interviewer Expects
- Knowing fs is a core built-in module
- Difference between sync and async methods
- Awareness of fs/promises and async/await usage
- Why blocking calls hurt server throughput
- When to use streams over readFile
Common Mistakes
- Using readFileSync inside request handlers and blocking the event loop
- Forgetting the 'utf8' encoding and getting a raw Buffer instead of a string
- Not handling the error argument in callbacks
- Loading huge files with readFile instead of streaming them
- Confusing fs (callback) with fs/promises (promise) APIs
Best Answer (HR Friendly)
“The fs module is Node.js's built-in toolkit for working with files — reading them, writing them, or deleting them. It offers non-blocking versions so the app can keep serving other users while a file operation finishes in the background.”
Code Example
const fs = require('fs/promises');
async function run() {
try {
// Write a file (creates or overwrites)
await fs.writeFile('notes.txt', 'Hello Node.js\n', 'utf8');
// Append another line
await fs.appendFile('notes.txt', 'Second line\n', 'utf8');
// Read it back as text
const data = await fs.readFile('notes.txt', 'utf8');
console.log(data);
} catch (err) {
console.error('File operation failed:', err.message);
}
}
run();const fs = require('fs');
const stream = fs.createReadStream('big-log.txt', 'utf8');
stream.on('data', (chunk) => {
console.log('Received chunk of', chunk.length, 'chars');
});
stream.on('end', () => console.log('Done reading'));
stream.on('error', (err) => console.error(err.message));Follow-up Questions
- What is the difference between fs.readFile and fs.readFileSync?
- When would you use a read stream instead of fs.readFile?
- How does fs.promises differ from the callback-based fs API?
- What does the encoding argument change in fs.readFile?
- How would you check if a file exists before reading it?
MCQ Practice
1. Which fs method blocks the event loop until it completes?
Synchronous methods like fs.readFileSync block the entire process until the disk operation finishes, so they should be avoided in servers.
2. What does fs.readFile return if you omit the encoding argument?
Without an encoding such as 'utf8', fs.readFile returns the raw bytes as a Buffer object rather than a decoded string.
3. Which approach is best for reading a very large file with minimal memory use?
createReadStream reads the file in small chunks, so memory usage stays low regardless of the file's total size.
Flash Cards
How do you get promise-based fs methods? — Require 'fs/promises' (or use fs.promises) to get methods that return promises for async/await.
Why avoid readFileSync in a server? — It blocks the event loop, stalling every other request until the disk read completes.
What does appendFile do? — It adds data to the end of a file, creating the file first if it does not already exist.
When should you use createReadStream? — For large files, so data flows in chunks instead of loading the whole file into memory.