Working with the File System in JavaScript (Node.js)
In modern web development, JavaScript has long moved beyond the browser. Thanks to the Node.js platform, developers can create server-side applications, work with databases, and, of course, interact with the file system. The ability to read, write, delete, and move files is one of the key skills of any backend developer. In this article, we will thoroughly examine how to work with the file system in JavaScript on Node.js, using the built-in fs module and its modern promise-based version fs/promises.
This material will be useful both for beginners just starting to learn Node.js and for experienced developers looking to systematize their knowledge. All code examples can be run in your development environment.
Importing the fs Module and Basic Methods
To work with the file system in Node.js, the built-in fs (file system) module is used. It does not need to be installed separately — it is available immediately after installing Node.js. It is imported in the standard way:
const fs = require('fs');However, in modern JavaScript (ES6+) and Node.js (starting from version 14), it is recommended to use the ES modules syntax and work with the promise-based version fs/promises. This allows you to avoid "callback hell" and write cleaner, asynchronous code using async/await.
import * as fs from 'fs/promises';// orconst fs = require('fs/promises');The main methods of the fs module are divided into three categories:
- Synchronous — block the execution thread (e.g.,
fs.readFileSync()). Used rarely, mainly in initialization scripts. - Asynchronous with callbacks — the traditional Node.js style (e.g.,
fs.readFile()). - Asynchronous with promises — the modern style (
fs/promises). Recommended for most tasks.
Reading Files in Node.js
Let's start with the most common action — reading the contents of a file. We'll look at two approaches: using callbacks and using promises.
Reading via Callbacks (Traditional Way)
const fs = require('fs');
fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.error('Error reading file:', err); return; } console.log('File contents:', data);});Note: we pass the 'utf8' encoding as the second argument. If it is not specified, the data will be returned as a binary buffer (Buffer).
Reading via Promises (Recommended Way)
import { readFile } from 'fs/promises';
async function readExample() { try { const data = await readFile('example.txt', 'utf8'); console.log('File contents:', data); } catch (err) { console.error('Error reading file:', err); }}
readExample();The code has become cleaner and more understandable. Errors are handled via try/catch, which is familiar to developers experienced with other languages.
Writing Data to a File
Writing to a file is the second most important operation. In Node.js, there are two main methods: writeFile (overwrites the file) and appendFile (adds data to the end of the file).
Overwriting a File
import { writeFile } from 'fs/promises';
async function writeExample() { try { await writeFile('output.txt', 'Hello, world!', 'utf8'); console.log('File successfully written'); } catch (err) { console.error('Error writing:', err); }}
writeExample();If the file output.txt does not exist, it will be created automatically. If it exists, its contents will be completely overwritten.