Node.js File System Module
The fs module lets you read, write, and manage files on the filesystem. It provides both callback-based and promise-based APIs.
Two styles
Callback style is the original API. You will see it in older code.
fs.promises with async/await is the modern approach. It is cleaner and easier to reason about. Prefer this in new code.
Importing
// CommonJS
const fs = require('fs');
const { readFile, writeFile } = require('fs/promises'); // promise API
// ES modules
import fs from 'node:fs';
import { readFile, writeFile } from 'node:fs/promises';
Reading files
Callback style:
const fs = require('fs');
fs.readFile('./docs/blog.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
Async/await (recommended):
import { readFile } from 'node:fs/promises';
const data = await readFile('./docs/blog.txt', 'utf8');
console.log(data);
If you omit the encoding, you get a Buffer instead of a string. Pass 'utf8' to get the text content directly.
Writing files
Callback:
fs.writeFile('./docs/blog.txt', 'Hello there', (err) => {
if (err) throw err;
console.log('File written');
});
Async/await:
import { writeFile } from 'node:fs/promises';
await writeFile('./docs/blog.txt', 'Hello there');
console.log('File written');
writeFile() creates the file if it does not exist and overwrites it if it does.
Appending to a file
import { appendFile } from 'node:fs/promises';
await appendFile('./docs/blog.txt', '\nNew line added');
Renaming a file
import { rename } from 'node:fs/promises';
await rename('./docs/blog.txt', './docs/newblog.txt');
Deleting a file
import { unlink } from 'node:fs/promises';
await unlink('./docs/blog.txt');
Checking if a file exists
With async/await:
import { access } from 'node:fs/promises';
try {
await access('./docs/blog.txt');
console.log('File exists');
} catch {
console.log('File does not exist');
}
With the synchronous method (useful in scripts where async is not needed):
import fs from 'node:fs';
if (fs.existsSync('./docs/blog.txt')) {
console.log('File exists');
}
Working with directories
Create a folder
import { mkdir } from 'node:fs/promises';
await mkdir('./images', { recursive: true }); // recursive: true avoids error if folder already exists
Delete a folder
fs.rmdir() is deprecated. Use fs.rm() instead:
import { rm } from 'node:fs/promises';
await rm('./images', { recursive: true });
Streams
For large files, loading the entire content into memory at once is slow and wasteful. Streams let you process data in chunks as it arrives.
Read stream:
const fs = require('fs');
const readStream = fs.createReadStream('./docs/blog3.txt', { encoding: 'utf8' });
readStream.on('data', (chunk) => {
console.log('-- New Chunk --');
console.log(chunk);
});
Writing a stream:
const fs = require('fs');
const readStream = fs.createReadStream('./docs/blog3.txt', { encoding: 'utf8' });
const writeStream = fs.createWriteStream('./docs/blog4.txt');
readStream.on('data', (chunk) => {
writeStream.write(chunk);
});
Using pipe() to connect a readable stream to a writable stream (shorter version):
const fs = require('fs');
const readStream = fs.createReadStream('./docs/blog3.txt', { encoding: 'utf8' });
const writeStream = fs.createWriteStream('./docs/blog4.txt');
readStream.pipe(writeStream);
For more methods, see the fs documentation .
What to read next
- Path Module
: building safe file paths to use with
fs - Core Modules : overview of all built-in modules