readFile and writeFile handle whole files: Node opens the file, moves its bytes, and closes it. Pass an encoding and you get a string; leave it off and you get a Buffer, which is what you want for images and archives.
import { writeFile, appendFile, readFile, open, rm } from 'node:fs/promises';
const file = 'notes.txt';
await writeFile(file, 'first line\n', 'utf8'); // creates or truncates
await appendFile(file, 'second line\n'); // utf8 is the default
console.log('text :', JSON.stringify(await readFile(file, 'utf8')));
try {
await writeFile(file, 'clobbered', { flag: 'wx' }); // 'x' = fail if it exists
} catch (err) {
console.log('flag :', err.code, '-', err.syscall, 'refused to truncate');
}
const handle = await open(file, 'r'); // one descriptor, many reads
try {
const { bytesRead, buffer } = await handle.read({ length: 4, position: 6 });
console.log('handle:', (await handle.stat()).size, 'bytes, read',
buffer.subarray(0, bytesRead) + '');
} finally {
await handle.close();
}
await rm(file, { force: true });text : "first line\nsecond line\n" flag : EEXIST - open refused to truncate handle: 23 bytes, read line
The flag option takes C's open flags: 'w' truncates, 'a' appends, 'r' reads, and adding x turns "create it" into "create it or fail." 'wx' claims a lock file without a check-then-write race, because the kernel enforces the exclusivity, not your code.
open() returns a FileHandle when you need several operations on one file — read a header, seek, read a record. Every handle must be closed, and try/finally guarantees it: a leaked descriptor lives until the process exits, and EMFILE errors under load are miserable to diagnose.
Three more operations finish the set. rename(from, to) moves a file, atomically within one volume. cp(src, dest, { recursive: true }) copies a tree; it lost its experimental label in Node 22.3.0. rm(path, { recursive: true, force: true }) is the rm -rf equivalent — and rmdir's own recursive option, deprecated since Node 14.14.0, was removed in Node 25, so rm is now the only built-in way to delete a non-empty directory.