Node.js File System
The Node.js file system module, fs, lets you work with files and folders on your computer or server. Modern code uses node:fs/promises with async/await. The fs module also has synchronous versions (readFileSync) that block the program, which are fine for small scripts but should be avoided inside servers.
Writing and Reading Files
writeFile creates the file or replaces its content. appendFile adds to the end. Passing "utf8" to readFile returns a string; without it you get a Buffer of raw bytes.
import { writeFile, readFile, appendFile } from 'node:fs/promises';
await writeFile('log.txt', 'Server started\n');
await appendFile('log.txt', 'User logged in\n');
const text = await readFile('log.txt', 'utf8');
console.log(text);Server started User logged in
Working with JSON Files
import { readFile, writeFile } from 'node:fs/promises';
const config = { port: 3000, debug: true };
await writeFile('config.json', JSON.stringify(config, null, 2));
const loaded = JSON.parse(await readFile('config.json', 'utf8'));
console.log(loaded.port);3000
Folders: Create, List and Remove
recursive: true creates parent folders as needed. rm with recursive deletes a folder and everything inside it, so use it carefully.
import { mkdir, readdir, rm } from 'node:fs/promises';
await mkdir('uploads/images', { recursive: true });
await writeFile('uploads/images/a.png', '');
await writeFile('uploads/readme.txt', 'hi');
const entries = await readdir('uploads', { withFileTypes: true });
for (const e of entries) {
console.log(e.isDirectory() ? '[dir] ' : '[file]', e.name);
}
await rm('uploads', { recursive: true, force: true });[dir] images [file] readme.txt
Checking if a File Exists
Use stat or access inside try/catch. A missing file throws an error with code ENOENT.
import { stat } from 'node:fs/promises';
async function exists(path) {
try {
await stat(path);
return true;
} catch (err) {
if (err.code === 'ENOENT') return false;
throw err;
}
}
console.log(await exists('package.json'));
console.log(await exists('missing.txt'));true false
Other fs Functions
- rename(old, new) — rename or move a file
- copyFile(src, dest) — copy a file
- unlink(path) — delete a single file
- stat(path) — size, dates, isFile(), isDirectory()
- watch(path) — get notified when files change
- createReadStream / createWriteStream — process large files piece by piece
Streams for Large Files
readFile loads the whole file into memory. For big files such as logs or videos, use streams, which handle the data in chunks. For example, pipeline(createReadStream("big.log"), createGzip(), createWriteStream("big.log.gz")) from node:stream/promises compresses a file of any size with low memory use.
Frequently asked questions
What is the difference between readFile and readFileSync?
readFile is asynchronous and lets Node do other work while reading. readFileSync blocks everything until it finishes, which is acceptable in startup scripts but bad in a server handling requests.
How do I check if a file exists in Node.js?
Call fs.promises.stat or access in a try/catch and treat an ENOENT error as "does not exist". The synchronous fs.existsSync is also available for simple scripts.
Why does readFile return a Buffer?
Without an encoding, Node returns raw bytes as a Buffer. Pass "utf8" as the second argument to get a string.