Node.js File System — Complete Guide to Reading, Writing, and Managing Files
In this tutorial, you will learn about Node.js File System. We cover key concepts, practical examples, and best practices to help you master this topic.
The Node.js fs (file system) module provides APIs for interacting with the file system, enabling reading, writing, deleting, and monitoring files and directories.
What You'll Learn
By the end of this tutorial, you'll use the fs module for synchronous and async file operations, directory management, file stats, watching files, and the promises API.
Why File System Module Matters
Most server applications need to read configuration files, write logs, Process uploads, or manage data files. The fs module is essential for these operations in tools like DodaZIP's file conversion pipeline.
Real-World Use
A log processing service reads multiple log files, parses entries, writes summary reports, and monitors a directory for new log files to process automatically.
FS Module Learning Path
flowchart LR
A[Path Module] --> B[File System]
B --> C[Streams]
C --> D[Buffers]
D --> E[Express.js]
A --> F{You Are Here}
style F fill:#f90,color:#fff
Reading Files
The fs module provides three patterns: synchronous, callback, and promise-based.
import fs from "node:fs";
import fsPromises from "node:fs/promises";
// Synchronous (blocks the event loop)
const data = fs.readFileSync("config.json", "utf8");
console.log(data);
// Callback (non-blocking)
fs.readFile("config.json", "utf8", (err, data) => {
if (err) throw err;
console.log(data);
});
// Promise (recommended)
const config = await fsPromises.readFile("config.json", "utf8");
console.log(config);
Writing Files
import fsPromises from "node:fs/promises";
await fsPromises.writeFile("output.txt", "Hello, world!", "utf8");
console.log("File written");
await fsPromises.appendFile("log.txt", `[${new Date().toISOString()}] Event logged\n`);
console.log("Appended");
Directory Operations
import fsPromises from "node:fs/promises";
// Create directory
await fsPromises.mkdir("data/logs", { recursive: true });
// Read directory
const files = await fsPromises.readdir("./data");
console.log(files); // ['logs', 'config.json']
// Remove directory
await fsPromises.rmdir("data/temp");
// Remove recursively
await fsPromises.rm("data/temp", { recursive: true, force: true });
File Statistics
import fsPromises from "node:fs/promises";
const stats = await fsPromises.stat("config.json");
console.log(stats.isFile()); // true
console.log(stats.isDirectory()); // false
console.log(stats.size); // 1240 (bytes)
console.log(stats.mtime); // Last modified date
Watching Files
import fs from "node:fs";
fs.watch("data/logs", (eventType, filename) => {
console.log(`File ${filename} changed: ${eventType}`);
});
File Copy and Rename
import fsPromises from "node:fs/promises";
await fsPromises.copyFile("source.txt", "backup.txt");
await fsPromises.rename("temp.txt", "final.txt");
Common Mistakes
1. Using Sync Methods in Server Request Handlers
readFileSync blocks the event loop. In a server, this freezes all requests until the file is read. Always use async methods.
2. Not Checking File Existence
Always handle the error case or check existence before operations.
3. Forgetting to Handle Errors
An unhandled error crashes the process. Always wrap in try/catch or provide error callbacks.
4. Hardcoding File Paths
Use path.join with __dirname or process.cwd() for cross-platform compatibility.
5. Opening Too Many Files
File descriptors are limited. Stream large files instead of reading them entirely into memory.
Practice Questions
1. What is the difference between readFile and createReadStream?
readFile loads the entire file into memory. createReadStream processes data in chunks, suitable for large files.
2. Which fs API should you use in a production web server?
The promise-based API (fs/promises) offers clean async/await syntax and proper error handling without blocking.
3. How do you create nested directories safely?
Use fsPromises.mkdir(path, { recursive: true }). It creates all parent directories if they don't exist.
4. What does fs.watch do?
It monitors a file or directory for changes and fires a callback when modifications occur.
5. Challenge: Write a script that watches a directory and copies new files to a backup location.
import fs from "node:fs";
import fsPromises from "node:fs/promises";
import path from "node:path";
const watchDir = "./incoming";
const backupDir = "./backup";
await fsPromises.mkdir(backupDir, { recursive: true });
fs.watch(watchDir, async (event, filename) => {
if (event === "rename") {
const src = path.join(watchDir, filename);
const dest = path.join(backupDir, filename);
await fsPromises.copyFile(src, dest);
console.log(`Backed up ${filename}`);
}
});
FAQ
Mini Project: Simple Logger
Build a logging module that appends timestamped entries to a log file with automatic rotation.
import fsPromises from "node:fs/promises";
import path from "node:path";
class Logger {
constructor(logDir = "./logs") {
this.logDir = logDir;
}
async log(level, message) {
await fsPromises.mkdir(this.logDir, { recursive: true });
const filePath = path.join(this.logDir, `${new Date().toISOString().split("T")[0]}.log`);
const entry = `[${new Date().toISOString()}] [${level}] ${message}\n`;
await fsPromises.appendFile(filePath, entry);
}
}
const logger = new Logger();
await logger.log("INFO", "Server started on port 3000");
await logger.log("ERROR", "Connection refused");
What's Next
Node.js Streams Node.js Buffers Express.js
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro