Topic 16 of 55
File
Overview
The fs module provides synchronous, callback, and promise-based APIs for file operations. fs/promises (Node 14+) is the modern standard for async file operations with clean async/await syntax.
Syntax
javascript
import { readFile, writeFile, mkdir, stat, readdir, unlink } from "fs/promises";
import { existsSync } from "fs";
// Read file
const content = await readFile("./data.json", "utf8");
const data = JSON.parse(content);
// Write file (creates or overwrites)
await writeFile("./output.json", JSON.stringify(data, null, 2), "utf8");
// Create directories (recursive)
await mkdir("./uploads/2024/01", { recursive: true });
// Check if file exists
const exists = existsSync("./config.env");
// File info
const stats = await stat("./large-file.csv");
console.log(stats.size, stats.isFile(), stats.mtime);
// List directory
const files = await readdir("./uploads");
// Delete file
await unlink("./temp.txt");Common Pitfalls
- Never use sync fs methods (readFileSync) in request handlers — they block the event loop and kill concurrency.
- fs.existsSync followed by file operation is a race condition — use try/catch on the operation directly instead.
- Interview tip: Use path.join() instead of string concatenation for paths — it handles OS differences and prevents path traversal attacks.
Real-World Example
A file upload handler that saves files with validation
example
javascript
import { writeFile, mkdir } from "fs/promises";
import path from "path";
import crypto from "crypto";
const UPLOAD_DIR = "./uploads";
const MAX_SIZE_MB = 10;
async function saveUploadedFile(buffer, originalName, userId) {
if (buffer.byteLength > MAX_SIZE_MB * 1024 * 1024) {
throw new Error("File exceeds " + MAX_SIZE_MB + "MB limit");
}
const ext = path.extname(originalName).toLowerCase();
const ALLOWED = [".jpg", ".jpeg", ".png", ".pdf", ".docx"];
if (!ALLOWED.includes(ext)) {
throw new Error("File type " + ext + " not allowed");
}
const userDir = path.join(UPLOAD_DIR, userId);
await mkdir(userDir, { recursive: true });
const uniqueName = crypto.randomUUID() + ext;
const filePath = path.join(userDir, uniqueName);
await writeFile(filePath, buffer);
return { path: filePath, name: uniqueName, size: buffer.byteLength };
}