A drop-in replacement for fs, making various improvements.
npx @tessl/cli install tessl/npm-graceful-fs@4.2.0Graceful FS is a drop-in replacement for Node.js's built-in fs module that makes filesystem operations more resilient to errors and cross-platform inconsistencies. It implements intelligent retry mechanisms for EMFILE errors, handles platform-specific quirks like Windows antivirus interference, and provides fallbacks for missing filesystem operations.
npm install graceful-fsconst fs = require('graceful-fs');For global patching (use with caution):
const fs = require('fs');
const gracefulFs = require('graceful-fs');
gracefulFs.gracefulify(fs);const fs = require('graceful-fs');
// All standard fs operations work as normal, but with enhanced error handling
fs.readFile('package.json', 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err);
return;
}
console.log('File contents:', data);
});
// File operations are automatically retried on EMFILE/ENFILE errors
fs.writeFile('output.txt', 'Hello World', (err) => {
if (err) {
console.error('Error writing file:', err);
return;
}
console.log('File written successfully');
});Graceful FS enhances the standard Node.js fs module with:
All standard Node.js fs methods are available with enhanced error handling and retry logic. Operations are automatically retried on transient errors and queued when file descriptor limits are reached.
/**
* Read entire file contents with EMFILE/ENFILE retry
* @param path - File path (string|Buffer|URL|number)
* @param options - Encoding or options object {encoding, flag}
* @param callback - (err, data) => void
*/
function readFile(path, options, callback);
function readFileSync(path, options);
/**
* Write data to file with EMFILE/ENFILE retry
* @param path - File path (string|Buffer|URL|number)
* @param data - Data to write (string|Buffer|TypedArray|DataView)
* @param options - Encoding or options object {encoding, mode, flag}
* @param callback - (err) => void
*/
function writeFile(path, data, options, callback);
function writeFileSync(path, data, options);
/**
* Append data to file with EMFILE/ENFILE retry
* @param path - File path (string|Buffer|URL|number)
* @param data - Data to append (string|Buffer)
* @param options - Encoding or options object {encoding, mode, flag}
* @param callback - (err) => void
*/
function appendFile(path, data, options, callback);
function appendFileSync(path, data, options);
/**
* Copy file with EMFILE/ENFILE retry
* @param src - Source file path (string|Buffer|URL)
* @param dest - Destination file path (string|Buffer|URL)
* @param flags - Copy flags (number, optional)
* @param callback - (err) => void
*/
function copyFile(src, dest, flags, callback);
function copyFileSync(src, dest, flags);
/**
* Open file with EMFILE/ENFILE retry and queue management
* @param path - File path (string|Buffer|URL)
* @param flags - File open flags (string|number)
* @param mode - File mode (integer, optional)
* @param callback - (err, fd) => void
*/
function open(path, flags, mode, callback);
function openSync(path, flags, mode);
/**
* Close file descriptor with queue management and retry processing
* @param fd - File descriptor (integer)
* @param callback - (err) => void
*/
function close(fd, callback);
function closeSync(fd);
/**
* Read from file descriptor with EAGAIN retry (up to 10 attempts)
* @param fd - File descriptor (integer)
* @param buffer - Buffer to read into
* @param offset - Buffer offset to start writing at
* @param length - Number of bytes to read
* @param position - File position to read from (null for current position)
* @param callback - (err, bytesRead, buffer) => void
*/
function read(fd, buffer, offset, length, position, callback);
function readSync(fd, buffer, offset, length, position);
/**
* Rename file with Windows antivirus retry logic (up to 60s on Windows)
* @param from - Current file path (string|Buffer|URL)
* @param to - New file path (string|Buffer|URL)
* @param callback - (err) => void
*/
function rename(from, to, callback);
function renameSync(from, to);Directory operations with improved error handling and consistent behavior across platforms.
/**
* Read directory contents with EMFILE/ENFILE retry and automatic sorting
* @param path - Directory path (string|Buffer|URL)
* @param options - Encoding or options object {encoding, withFileTypes}
* @param callback - (err, files) => void where files are automatically sorted
*/
function readdir(path, options, callback);
function readdirSync(path, options);Enhanced stream classes with improved error handling and retry logic.
/**
* Enhanced readable file stream with EMFILE/ENFILE retry logic
* @extends require('stream').Readable
*/
class ReadStream extends require('stream').Readable {
/**
* @param path - File path (string|Buffer|URL)
* @param options - Stream options {flags, encoding, fd, mode, autoClose, emitClose, start, end, highWaterMark}
*/
constructor(path, options);
/** Enhanced open method with retry logic */
open();
}
/**
* Enhanced writable file stream with EMFILE/ENFILE retry logic
* @extends require('stream').Writable
*/
class WriteStream extends require('stream').Writable {
/**
* @param path - File path (string|Buffer|URL)
* @param options - Stream options {flags, encoding, fd, mode, autoClose, emitClose, start, highWaterMark}
*/
constructor(path, options);
/** Enhanced open method with retry logic */
open();
}
/**
* Create enhanced readable stream with retry logic
* @param path - File path (string|Buffer|URL)
* @param options - Stream options object
* @returns ReadStream instance
*/
function createReadStream(path, options);
/**
* Create enhanced writable stream with retry logic
* @param path - File path (string|Buffer|URL)
* @param options - Stream options object
* @returns WriteStream instance
*/
function createWriteStream(path, options);
/**
* Legacy alias for ReadStream (for compatibility)
*/
class FileReadStream extends ReadStream {}
/**
* Legacy alias for WriteStream (for compatibility)
*/
class FileWriteStream extends WriteStream {}File permission and ownership operations with enhanced error tolerance for non-root users. These methods gracefully ignore EINVAL, EPERM errors when not running as root, and ENOSYS errors on filesystems that don't support the operation.
/**
* Change file ownership, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
* @param path - File path (string|Buffer|URL)
* @param uid - User ID (integer)
* @param gid - Group ID (integer)
* @param callback - (err) => void
*/
function chown(path, uid, gid, callback);
function chownSync(path, uid, gid);
/**
* Change file ownership by descriptor, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
* @param fd - File descriptor (integer)
* @param uid - User ID (integer)
* @param gid - Group ID (integer)
* @param callback - (err) => void
*/
function fchown(fd, uid, gid, callback);
function fchownSync(fd, uid, gid);
/**
* Change symlink ownership, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
* @param path - Symlink path (string|Buffer|URL)
* @param uid - User ID (integer)
* @param gid - Group ID (integer)
* @param callback - (err) => void
*/
function lchown(path, uid, gid, callback);
function lchownSync(path, uid, gid);
/**
* Change file permissions, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
* @param path - File path (string|Buffer|URL)
* @param mode - Permission mode (integer)
* @param callback - (err) => void
*/
function chmod(path, mode, callback);
function chmodSync(path, mode);
/**
* Change file permissions by descriptor, gracefully ignores EINVAL/EPERM for non-root, ENOSYS
* @param fd - File descriptor (integer)
* @param mode - Permission mode (integer)
* @param callback - (err) => void
*/
function fchmod(fd, mode, callback);
function fchmodSync(fd, mode);
/**
* Change symlink permissions (polyfilled or noop if unavailable)
* @param path - Symlink path (string|Buffer|URL)
* @param mode - Permission mode (integer)
* @param callback - (err) => void
*/
function lchmod(path, mode, callback);
function lchmodSync(path, mode);File stat operations with fixes for platform-specific issues like negative uid/gid values, converting them to proper unsigned 32-bit integers.
/**
* Get file statistics, fixes negative uid/gid values on older Node.js versions
* @param path - File path (string|Buffer|URL)
* @param options - Options object {bigint: boolean} (optional)
* @param callback - (err, stats) => void
*/
function stat(path, options, callback);
function statSync(path, options);
/**
* Get file statistics by descriptor, fixes negative uid/gid values
* @param fd - File descriptor (integer)
* @param options - Options object {bigint: boolean} (optional)
* @param callback - (err, stats) => void
*/
function fstat(fd, options, callback);
function fstatSync(fd, options);
/**
* Get symlink statistics without following, fixes negative uid/gid values
* @param path - Symlink path (string|Buffer|URL)
* @param options - Options object {bigint: boolean} (optional)
* @param callback - (err, stats) => void
*/
function lstat(path, options, callback);
function lstatSync(path, options);File timestamp operations with polyfills for missing platform functionality.
/**
* Change file access and modification times
* @param path - File path (string|Buffer|URL)
* @param atime - Access time (Date|number)
* @param mtime - Modification time (Date|number)
* @param callback - (err) => void
*/
function utimes(path, atime, mtime, callback);
function utimesSync(path, atime, mtime);
/**
* Change file times by descriptor
* @param fd - File descriptor (integer)
* @param atime - Access time (Date|number)
* @param mtime - Modification time (Date|number)
* @param callback - (err) => void
*/
function futimes(fd, atime, mtime, callback);
function futimesSync(fd, atime, mtime);
/**
* Change symlink times (polyfilled using futimes on opened symlink)
* @param path - Symlink path (string|Buffer|URL)
* @param atime - Access time (Date|number)
* @param mtime - Modification time (Date|number)
* @param callback - (err) => void
*/
function lutimes(path, atime, mtime, callback);
function lutimesSync(path, atime, mtime);Apply graceful-fs enhancements to any fs-like module.
/**
* Apply graceful-fs patches to any fs-like module or object
* @param fs - The fs module or fs-like object to patch
* @returns The patched fs object with graceful-fs enhancements
*/
function gracefulify(fs);Usage Example:
const fs = require('fs');
const gracefulFs = require('graceful-fs');
// Patch the global fs module
gracefulFs.gracefulify(fs);
// Now all fs operations use graceful-fs enhancements
fs.readFile('file.txt', callback);Enhanced process methods for better working directory handling.
/**
* Enhanced process.cwd with caching for better performance
* @returns string - Current working directory path
*/
process.cwd();
/**
* Enhanced process.chdir that clears cwd cache
* @param directory - Directory path to change to
*/
process.chdir(directory);Read-only access to the internal retry queue for debugging and monitoring.
/**
* Access to internal retry queue (read-only)
* @readonly
*/
fs[Symbol.for('graceful-fs.queue')];Graceful FS automatically handles several types of filesystem errors with sophisticated retry and tolerance mechanisms:
EMFILE/ENFILE Errors: File descriptor limit errors are automatically queued and retried
open(), readFile(), writeFile(), appendFile(), copyFile(), readdir()EAGAIN Errors: Temporary resource unavailable errors in read operations
read() and readSync() operationsWindows Rename Retry Logic: Special handling for antivirus software interference
EACCES, EPERM, EBUSY on Windows onlyrename() operations on WindowsEINVAL/EPERM: Permission errors in ownership/permission operations are gracefully ignored for non-root users
chown(), fchown(), lchown(), chmod(), fchmod(), lchmod() operationsENOSYS: Errors indicating filesystem doesn't support an operation are ignored
All enhanced methods maintain the same API as the standard Node.js fs module, making graceful-fs a true drop-in replacement.
In addition to the enhanced methods documented above, graceful-fs provides access to ALL standard Node.js fs methods with the same signatures and behavior. Methods not explicitly enhanced by graceful-fs are passed through unchanged, ensuring complete compatibility with existing code. This includes methods like:
access(), accessSync()exists(), existsSync()mkdir(), mkdirSync()rmdir(), rmdirSync()unlink(), unlinkSync()symlink(), symlinkSync()readlink(), readlinkSync()truncate(), truncateSync()ftruncate(), ftruncateSync()watch(), watchFile(), unwatchFile()realpath(), realpathSync()mkdtemp(), mkdtempSync()All methods retain their original signatures, callback patterns, and error handling, with graceful-fs enhancements applied only where beneficial for reliability and cross-platform compatibility.