fs/promisesThe built-in node:fs/promises module lets Node.js scripts read, write, append, list, and delete files on disk using clean async / await promises. Unlike legacy callback-based fs methods or blocking *Sync helpers, fs/promises keeps your server event loop responsive while disk operations run in the background.
Pass 'utf8' encoding when reading text files so readFile() returns a JavaScript string instead of a raw binary Buffer. Use { recursive: true } with mkdir() so nested directories are created safely without throwing if they already exist.
import { mkdir, readFile, writeFile, appendFile } from 'node:fs/promises';
import path from 'node:path';
async function saveAndReadNote() {
const dataDir = path.join(import.meta.dirname, 'data');
const notePath = path.join(dataDir, 'notes.txt');
await mkdir(dataDir, { recursive: true });
await writeFile(notePath, 'First line saved.
', 'utf8');
await appendFile(notePath, 'Second line appended.
', 'utf8');
const content = await readFile(notePath, 'utf8');
console.log(content);
}
saveAndReadNote().catch((err) => console.error('FS error:', err.message));
ENOENT) Without Race ConditionsAvoid calling fs.existsSync() right before readFile(), because another process could delete or move the file between those two checks. Instead, call readFile() directly inside try / catch and inspect err.code === 'ENOENT'.
fs.readFileSync() inside API request handlers: Synchronous disk methods block the entire Node.js thread until the OS finishes reading, stalling every other concurrent user. Reserve *Sync methods strictly for startup configs or CLI scripts.path.join() alone: path.join('/uploads', '../../.env') resolves outside /uploads. Verify resolvedPath.startsWith(safeBaseDir + path.sep) before touching disk.readFile(): readFile() buffers the whole file in memory. Switch to fs.createReadStream() for large files.node:fs and node:fs/promises?node:fs exports callback and synchronous methods, whereas node:fs/promises exports promise-returning functions built specifically for async / await.
Use await fs.rm(filePath, { force: true }) so missing files do not throw ENOENT errors.
Call await fs.readdir(dirPath, { withFileTypes: true }), which returns Dirent objects with .isFile() and .isDirectory() helpers.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.