Back to results for “File System (fs) Module”
Node.js › File System (fs) Module

What is the difference between the synchronous, callback-based, and promise-based variants of Node's fs module methods?

Beginner

Answer

Every core fs operation is available in three forms: a synchronous version (like fs.readFileSync, which blocks the entire event loop until it completes -- appropriate only for startup scripts or CLI tools, never for a running server handling concurrent requests), a callback-based version (like fs.readFile, non-blocking, using the classic error-first callback), and a promise-based version (via require('node:fs/promises'), non-blocking, usable directly with async/await, generally the preferred style for modern application code).
const fsSync = require('node:fs');
const fs = require('node:fs/promises');

// Blocks the event loop -- avoid in request handlers
const data1 = fsSync.readFileSync('config.json', 'utf-8');

// Non-blocking, modern async/await style
const data2 = await fs.readFile('config.json', 'utf-8');
Real-world example A web server accidentally used fs.readFileSync() inside a request handler to serve an uploaded file, causing every other concurrent request to stall while any single file read was in progress; switching to fs.readFile() from fs/promises resolved the bottleneck by letting the event loop continue serving other requests during the I/O wait.

Common follow-ups: In what specific scenario is fs.readFileSync() actually the appropriate, correct choice rather than a mistake?;How does the promise-based fs/promises API compare in performance to the callback-based version, given both are non-blocking?