On this page

Callback API

History

The callback APIs perform all operations asynchronously, without blocking the event loop, then invoke a callback function upon completion or error.

The callback APIs use the underlying Node.js threadpool to perform file system operations off the event loop thread. These operations are not synchronized or threadsafe. Care must be taken when performing multiple concurrent modifications on the same file or data corruption may occur.

fs.access(path, mode?, callback): void
Attributes
path:string | Buffer | URL
mode?:integer
Default: fs.constants.F_OK
callback:Function
err:Error

Tests a user's permissions for the file or directory specified by path. The mode argument is an optional integer that specifies the accessibility checks to be performed. mode should be either the value fs.constants.F_OK or a mask consisting of the bitwise OR of any of fs.constants.R_OK, fs.constants.W_OK, and fs.constants.X_OK (e.g. fs.constants.W_OK | fs.constants.R_OK). Check File access constants for possible values of mode.

The final argument, callback, is a callback function that is invoked with a possible error argument. If any of the accessibility checks fail, the error argument will be an Error object. The following examples check if package.json exists, and if it is readable or writable.

import { access, constants } from 'node:fs';

const file = 'package.json';

// Check if the file exists in the current directory.
access(file, constants.F_OK, (err) => {
  console.log(`${file} ${err ? 'does not exist' : 'exists'}`);
});

// Check if the file is readable.
access(file, constants.R_OK, (err) => {
  console.log(`${file} ${err ? 'is not readable' : 'is readable'}`);
});

// Check if the file is writable.
access(file, constants.W_OK, (err) => {
  console.log(`${file} ${err ? 'is not writable' : 'is writable'}`);
});

// Check if the file is readable and writable.
access(file, constants.R_OK | constants.W_OK, (err) => {
  console.log(`${file} ${err ? 'is not' : 'is'} readable and writable`);
});

Do not use fs.access() to check for the accessibility of a file before calling fs.open(), fs.readFile(), or fs.writeFile(). Doing so introduces a race condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file is not accessible.

write (NOT RECOMMENDED)

import { access, open, close } from 'node:fs';

access('myfile', (err) => {
  if (!err) {
    console.error('myfile already exists');
    return;
  }

  open('myfile', 'wx', (err, fd) => {
    if (err) throw err;

    try {
      writeMyData(fd);
    } finally {
      close(fd, (err) => {
        if (err) throw err;
      });
    }
  });
});

write (RECOMMENDED)

import { open, close } from 'node:fs';

open('myfile', 'wx', (err, fd) => {
  if (err) {
    if (err.code === 'EEXIST') {
      console.error('myfile already exists');
      return;
    }

    throw err;
  }

  try {
    writeMyData(fd);
  } finally {
    close(fd, (err) => {
      if (err) throw err;
    });
  }
});

read (NOT RECOMMENDED)

import { access, open, close } from 'node:fs';
access('myfile', (err) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('myfile does not exist');
      return;
    }

    throw err;
  }

  open('myfile', 'r', (err, fd) => {
    if (err) throw err;

    try {
      readMyData(fd);
    } finally {
      close(fd, (err) => {
        if (err) throw err;
      });
    }
  });
});

read (RECOMMENDED)

import { open, close } from 'node:fs';

open('myfile', 'r', (err, fd) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('myfile does not exist');
      return;
    }

    throw err;
  }

  try {
    readMyData(fd);
  } finally {
    close(fd, (err) => {
      if (err) throw err;
    });
  }
});

The "not recommended" examples above check for accessibility and then use the file; the "recommended" examples are better because they use the file directly and handle the error, if any.

In general, check for the accessibility of a file only if the file will not be used directly, for example when its accessibility is a signal from another process.

On Windows, access-control policies (ACLs) on a directory may limit access to a file or directory. The fs.access() function, however, does not check the ACL and therefore may report that a path is accessible even if the ACL restricts the user from reading or writing to it.

fs.appendFile(path, data, options?, callback): void
Attributes
path:string | Buffer | URL | number
filename or file descriptor
data:string | Buffer
options:Object | string
encoding?:string | null
Default: 'utf8'
mode?:integer
Default: 0o666
flag?:string
See support of file system flags. Default: 'a'.
flush?:boolean
If true, the underlying file descriptor is flushed prior to closing it. Default: false.
callback:Function
err:Error

Asynchronously append data to a file, creating the file if it does not yet exist. data can be a string or a Buffer.

The mode option only affects the newly created file. See fs.open() for more details.

import { appendFile } from 'node:fs';

appendFile('message.txt', 'data to append', (err) => {
  if (err) throw err;
  console.log('The "data to append" was appended to file!');
});

If options is a string, then it specifies the encoding:

import { appendFile } from 'node:fs';

appendFile('message.txt', 'data to append', 'utf8', callback);

The path may be specified as a numeric file descriptor that has been opened for appending (using fs.open() or fs.openSync()). The file descriptor will not be closed automatically.

import { open, close, appendFile } from 'node:fs';

function closeFd(fd) {
  close(fd, (err) => {
    if (err) throw err;
  });
}

open('message.txt', 'a', (err, fd) => {
  if (err) throw err;

  try {
    appendFile(fd, 'data to append', 'utf8', (err) => {
      closeFd(fd);
      if (err) throw err;
    });
  } catch (err) {
    closeFd(fd);
    throw err;
  }
});
fs.chmod(path, mode, callback): void
Attributes
path:string | Buffer | URL
callback:Function
err:Error

Asynchronously changes the permissions of a file. No arguments other than a possible exception are given to the completion callback.

See the POSIX chmod(2) documentation for more detail.

import { chmod } from 'node:fs';

chmod('my_file.txt', 0o775, (err) => {
  if (err) throw err;
  console.log('The permissions for file "my_file.txt" have been changed!');
});

The mode argument used in both the fs.chmod() and fs.chmodSync() methods is a numeric bitmask created using a logical OR of the following constants:

ConstantOctalDescription
fs.constants.S_IRUSR0o400read by owner
fs.constants.S_IWUSR0o200write by owner
fs.constants.S_IXUSR0o100execute/search by owner
fs.constants.S_IRGRP0o40read by group
fs.constants.S_IWGRP0o20write by group
fs.constants.S_IXGRP0o10execute/search by group
fs.constants.S_IROTH0o4read by others
fs.constants.S_IWOTH0o2write by others
fs.constants.S_IXOTH0o1execute/search by others

An easier method of constructing the mode is to use a sequence of three octal digits (e.g. 765). The left-most digit (7 in the example), specifies the permissions for the file owner. The middle digit (6 in the example), specifies permissions for the group. The right-most digit (5 in the example), specifies the permissions for others.

NumberDescription
7read, write, and execute
6read and write
5read and execute
4read only
3write and execute
2write only
1execute only
0no permission

For example, the octal value 0o765 means:

  • The owner may read, write, and execute the file.
  • The group may read and write the file.
  • Others may read and execute the file.

When using raw numbers where file modes are expected, any value larger than 0o777 may result in platform-specific behaviors that are not supported to work consistently. Therefore constants like S_ISVTX, S_ISGID, or S_ISUID are not exposed in fs.constants.

Caveats: on Windows only the write permission can be changed, and the distinction among the permissions of group, owner, or others is not implemented.

fs.chown(path, uid, gid, callback): void
Attributes
path:string | Buffer | URL
callback:Function
err:Error

Asynchronously changes owner and group of a file. No arguments other than a possible exception are given to the completion callback.

See the POSIX chown(2) documentation for more detail.

fs.close(fd, callback?): void
Attributes
callback:Function
err:Error

Closes the file descriptor. No arguments other than a possible exception are given to the completion callback.

Calling fs.close() on any file descriptor (fd) that is currently in use through any other fs operation may lead to undefined behavior.

See the POSIX close(2) documentation for more detail.

fs.copyFile(src, dest, mode?, callback): void
Attributes
src:string | Buffer | URL
source filename to copy
dest:string | Buffer | URL
destination filename of the copy operation
mode?:integer
modifiers for copy operation. Default: 0.
callback:Function
err:Error

Asynchronously copies src to dest. By default, dest is overwritten if it already exists. No arguments other than a possible exception are given to the callback function. Node.js makes no guarantees about the atomicity of the copy operation. If an error occurs after the destination file has been opened for writing, Node.js will attempt to remove the destination.

Symbolic links are followed. If src is a symbolic link, the target file is copied. If dest is a symbolic link, the target file is overwritten unless mode contains fs.constants.COPYFILE_EXCL.

mode is an optional integer that specifies the behavior of the copy operation. It is possible to create a mask consisting of the bitwise OR of two or more values (e.g. fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE).

  • fs.constants.COPYFILE_EXCL: The copy operation will fail if dest already exists.
  • fs.constants.COPYFILE_FICLONE: The copy operation will attempt to create a copy-on-write reflink. If the platform does not support copy-on-write, then a fallback copy mechanism is used.
  • fs.constants.COPYFILE_FICLONE_FORCE: The copy operation will attempt to create a copy-on-write reflink. If the platform does not support copy-on-write, then the operation will fail.
import { copyFile, constants } from 'node:fs';

function callback(err) {
  if (err) throw err;
  console.log('source.txt was copied to destination.txt');
}

// destination.txt will be created or overwritten by default.
copyFile('source.txt', 'destination.txt', callback);

// By using COPYFILE_EXCL, the operation will fail if destination.txt exists.
copyFile('source.txt', 'destination.txt', constants.COPYFILE_EXCL, callback);
fs.cp(src, dest, options?, callback): void
Attributes
src:string | URL
source path to copy.
dest:string | URL
destination path to copy to.
options:Object
dereference?:boolean
dereference symlinks. Default: false.
errorOnExist?:boolean
when force is false, and the destination exists, throw an error. Default: false.
filter?:Function
Function to filter copied files/directories. Return true to copy the item, false to ignore it. When ignoring a directory, all of its contents will be skipped as well. Can also return a Promise that fulfills with true or false. Default: undefined.
src:string
source path to copy.
dest:string
destination path to copy to.
Returns:boolean | Promise
A value that is coercible to boolean or a Promise that fulfils with such value.
force?:boolean
overwrite existing file or directory. The copy operation will ignore errors if you set this to false and the destination exists. Use the errorOnExist option to change this behavior. Default: true.
mode?:integer
modifiers for copy operation. Default: 0. See mode flag of fs.copyFile().
preserveTimestamps?:boolean
When true timestamps from src will be preserved. Default: false.
recursive?:boolean
copy directories recursively Default: false
verbatimSymlinks?:boolean
When true, path resolution for symlinks will be skipped. Default: false
callback:Function
err:Error

Asynchronously copies the entire directory structure from src to dest, including subdirectories and files.

When copying a directory to another directory, globs are not supported and behavior is similar to cp dir1/ dir2/.

fs.createReadStream(path, options?): fs.ReadStream
Attributes
path:string | Buffer | URL
options:string | Object
flags?:string
See support of file system flags. Default: 'r'.
encoding?:string
Default: null
Default: null
mode?:integer
Default: 0o666
autoClose?:boolean
Default: true
emitClose?:boolean
Default: true
start:integer
end?:integer
Default: Infinity
highWaterMark?:integer
Default: 64 * 1024
fs?:Object | null
Default: null
signal?:AbortSignal | null
Default: null
windowsHandle?:bigint
A raw Win32 HANDLE value to read from, in place of fd. Windows only. Default: null

options can include start and end values to read a range of bytes from the file instead of the entire file. Both start and end are inclusive and start counting at 0, allowed values are in the [0, Number.MAX_SAFE_INTEGER] range. If fd is specified and start is omitted or undefined, fs.createReadStream() reads sequentially from the current file position. The encoding can be any one of those accepted by Buffer.

If fd is specified, ReadStream will ignore the path argument and will use the specified file descriptor. This means that no 'open' event will be emitted. fd should be blocking; non-blocking fds should be passed to net.Socket.

If fd points to a character device that only supports blocking reads (such as keyboard or sound card), read operations do not finish until data is available. This can prevent the process from exiting and the stream from closing naturally.

On Windows, a value passed in fd is interpreted as a CRT file descriptor. To use a raw Win32 HANDLE instead, such as an inherited anonymous pipe handle obtained from another process, pass it as windowsHandle. The handle is wrapped in a file descriptor that the stream owns and closes. The windowsHandle option throws on non-Windows platforms and cannot be combined with the fs option.

By default, the stream will emit a 'close' event after it has been destroyed. Set the emitClose option to false to change this behavior.

By providing the fs option, it is possible to override the corresponding fs implementations for open, read, and close. When providing the fs option, an override for read is required. If no fd is provided, an override for open is also required. If autoClose is true, an override for close is also required.

import { createReadStream } from 'node:fs';

// Create a stream from some character device.
const stream = createReadStream('/dev/input/event0');
setTimeout(() => {
  stream.close(); // This may not close the stream.
  // Artificially marking end-of-stream, as if the underlying resource had
  // indicated end-of-file by itself, allows the stream to close.
  // This does not cancel pending read operations, and if there is such an
  // operation, the process may still not be able to exit successfully
  // until it finishes.
  stream.push(null);
  stream.read(0);
}, 100);

If autoClose is false, then the file descriptor won't be closed, even if there's an error. It is the application's responsibility to close it and make sure there's no file descriptor leak. If autoClose is set to true (default behavior), on 'error' or 'end' the file descriptor will be closed automatically.

mode sets the file mode (permission and sticky bits), but only if the file was created.

An example to read the last 10 bytes of a file which is 100 bytes long:

import { createReadStream } from 'node:fs';

createReadStream('sample.txt', { start: 90, end: 99 });

If options is a string, then it specifies the encoding.

fs.createWriteStream(path, options?): fs.WriteStream
Attributes
path:string | Buffer | URL
options:string | Object
flags?:string
See support of file system flags. Default: 'w'.
encoding?:string
Default: 'utf8'
Default: null
mode?:integer
Default: 0o666
autoClose?:boolean
Default: true
emitClose?:boolean
Default: true
start:integer
fs?:Object | null
Default: null
signal?:AbortSignal | null
Default: null
highWaterMark?:number
flush?:boolean
If true, the underlying file descriptor is flushed prior to closing it. Default: false.
windowsHandle?:bigint
A raw Win32 HANDLE value to write to, in place of fd. Windows only. Default: null

options may also include a start option to allow writing data at some position past the beginning of the file, allowed values are in the [0, Number.MAX_SAFE_INTEGER] range. Modifying a file rather than replacing it may require the flags option to be set to r+ rather than the default w. The encoding can be any one of those accepted by Buffer.

If autoClose is set to true (default behavior) on 'error' or 'finish' the file descriptor will be closed automatically. If autoClose is false, then the file descriptor won't be closed, even if there's an error. It is the application's responsibility to close it and make sure there's no file descriptor leak.

On Windows, a value passed in fd is interpreted as a CRT file descriptor. To use a raw Win32 HANDLE instead, such as an inherited anonymous pipe handle obtained from another process, pass it as windowsHandle. The handle is wrapped in a file descriptor that the stream owns and closes. The windowsHandle option throws on non-Windows platforms and cannot be combined with the fs option.

By default, the stream will emit a 'close' event after it has been destroyed. Set the emitClose option to false to change this behavior.

By providing the fs option it is possible to override the corresponding fs implementations for open, write, writev, and close. Overriding write() without writev() can reduce performance as some optimizations (_writev()) will be disabled. When providing the fs option, overrides for at least one of write and writev are required. If no fd option is supplied, an override for open is also required. If autoClose is true, an override for close is also required.

Like fs.ReadStream, if fd is specified, fs.WriteStream will ignore the path argument and will use the specified file descriptor. This means that no 'open' event will be emitted. fd should be blocking; non-blocking fds should be passed to net.Socket.

If options is a string, then it specifies the encoding.

fs.exists(path, callback): void
Stability: 0Deprecated: Use fs.stat() or fs.access() instead.
Attributes
path:string | Buffer | URL
callback:Function
exists:boolean

Test whether or not the element at the given path exists by checking with the file system. Then call the callback argument with either true or false:

import { exists } from 'node:fs';

exists('/etc/passwd', (e) => {
  console.log(e ? 'it exists' : 'no passwd!');
});

The parameters for this callback are not consistent with other Node.js callbacks. Normally, the first parameter to a Node.js callback is an err parameter, optionally followed by other parameters. The fs.exists() callback has only one boolean parameter. This is one reason fs.access() is recommended instead of fs.exists().

If path is a symbolic link, it is followed. Thus, if path exists but points to a non-existent element, the callback will receive the value false.

Using fs.exists() to check for the existence of a file before calling fs.open(), fs.readFile(), or fs.writeFile() is not recommended. Doing so introduces a race condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file does not exist.

write (NOT RECOMMENDED)

import { exists, open, close } from 'node:fs';

exists('myfile', (e) => {
  if (e) {
    console.error('myfile already exists');
  } else {
    open('myfile', 'wx', (err, fd) => {
      if (err) throw err;

      try {
        writeMyData(fd);
      } finally {
        close(fd, (err) => {
          if (err) throw err;
        });
      }
    });
  }
});

write (RECOMMENDED)

import { open, close } from 'node:fs';
open('myfile', 'wx', (err, fd) => {
  if (err) {
    if (err.code === 'EEXIST') {
      console.error('myfile already exists');
      return;
    }

    throw err;
  }

  try {
    writeMyData(fd);
  } finally {
    close(fd, (err) => {
      if (err) throw err;
    });
  }
});

read (NOT RECOMMENDED)

import { open, close, exists } from 'node:fs';

exists('myfile', (e) => {
  if (e) {
    open('myfile', 'r', (err, fd) => {
      if (err) throw err;

      try {
        readMyData(fd);
      } finally {
        close(fd, (err) => {
          if (err) throw err;
        });
      }
    });
  } else {
    console.error('myfile does not exist');
  }
});

read (RECOMMENDED)

import { open, close } from 'node:fs';

open('myfile', 'r', (err, fd) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('myfile does not exist');
      return;
    }

    throw err;
  }

  try {
    readMyData(fd);
  } finally {
    close(fd, (err) => {
      if (err) throw err;
    });
  }
});

The "not recommended" examples above check for existence and then use the file; the "recommended" examples are better because they use the file directly and handle the error, if any.

In general, check for the existence of a file only if the file won't be used directly, for example when its existence is a signal from another process.

fs.fchmod(fd, mode, callback): void
Attributes
callback:Function
err:Error

Sets the permissions on the file. No arguments other than a possible exception are given to the completion callback.

See the POSIX fchmod(2) documentation for more detail.

fs.fchown(fd, uid, gid, callback): void
Attributes
callback:Function
err:Error

Sets the owner of the file. No arguments other than a possible exception are given to the completion callback.

See the POSIX fchown(2) documentation for more detail.

fs.fdatasync(fd, callback): void
Attributes
callback:Function
err:Error

Forces all currently queued I/O operations associated with the file to the operating system's synchronized I/O completion state. Refer to the POSIX fdatasync(2) documentation for details. No arguments other than a possible exception are given to the completion callback.

fs.fstat(fd, options?, callback): void
Attributes
options:Object
bigint?:boolean
Whether the numeric values in the returned fs.Stats object should be bigint. Default: false.
signal?:AbortSignal
An AbortSignal to cancel the operation. Default: undefined.
callback:Function
err:Error
stats:fs.Stats

Invokes the callback with the fs.Stats for the file descriptor.

See the POSIX fstat(2) documentation for more detail.

fs.fsync(fd, callback): void
Attributes
callback:Function
err:Error

Request that all data for the open file descriptor is flushed to the storage device. The specific implementation is operating system and device specific. Refer to the POSIX fsync(2) documentation for more detail. No arguments other than a possible exception are given to the completion callback.

fs.ftruncate(fd, len?, callback): void
Attributes
len?:integer
Default: 0
callback:Function
err:Error

Truncates the file descriptor. No arguments other than a possible exception are given to the completion callback.

See the POSIX ftruncate(2) documentation for more detail.

If the file referred to by the file descriptor was larger than len bytes, only the first len bytes will be retained in the file.

For example, the following program retains only the first four bytes of the file:

import { open, close, ftruncate } from 'node:fs';

function closeFd(fd) {
  close(fd, (err) => {
    if (err) throw err;
  });
}

open('temp.txt', 'r+', (err, fd) => {
  if (err) throw err;

  try {
    ftruncate(fd, 4, (err) => {
      closeFd(fd);
      if (err) throw err;
    });
  } catch (err) {
    closeFd(fd);
    if (err) throw err;
  }
});

If the file previously was shorter than len bytes, it is extended, and the extended part is filled with null bytes ('\0'):

If len is negative then 0 will be used.

fs.futimes(fd, atime, mtime, callback): void
Attributes
atime:number | string | Date
mtime:number | string | Date
callback:Function
err:Error

Change the file system timestamps of the object referenced by the supplied file descriptor. See fs.utimes().

fs.glob(pattern, options?, callback): void
Attributes
pattern:string | string[]
options:Object
cwd?:string | URL
current working directory. Default: process.cwd()
exclude?:Function | string[]
Function to filter out files/directories or a list of glob patterns to be excluded. If a function is provided, return true to exclude the item, false to include it. Default: undefined.
followSymlinks?:boolean
When true, symbolic links to directories are followed while expanding ** patterns. Default: false.
withFileTypes?:boolean
true if the glob should return paths as Dirents, false otherwise. Default: false.
callback:Function
err:Error
  • Retrieves the files matching the specified pattern.

When followSymlinks is enabled, detected symbolic link cycles are not traversed recursively.

import { glob } from 'node:fs';

glob('**/*.js', (err, matches) => {
  if (err) throw err;
  console.log(matches);
});
const { glob } = require('node:fs');

glob('**/*.js', (err, matches) => {
  if (err) throw err;
  console.log(matches);
});
fs.lchmod(path, mode, callback): void
Stability: 0Deprecated
Attributes

Changes the permissions on a symbolic link. No arguments other than a possible exception are given to the completion callback.

This method is only implemented on macOS.

See the POSIX lchmod(2) documentation for more detail.

fs.lchown(path, uid, gid, callback): void
Attributes
path:string | Buffer | URL
callback:Function
err:Error

Set the owner of the symbolic link. No arguments other than a possible exception are given to the completion callback.

See the POSIX lchown(2) documentation for more detail.

fs.lutimes(path, atime, mtime, callback): void
Attributes
path:string | Buffer | URL
atime:number | string | Date
mtime:number | string | Date
callback:Function
err:Error

Changes the access and modification times of a file in the same way as fs.utimes(), with the difference that if the path refers to a symbolic link, then the link is not dereferenced: instead, the timestamps of the symbolic link itself are changed.

No arguments other than a possible exception are given to the completion callback.

fs.link(existingPath, newPath, callback): void
Attributes
existingPath:string | Buffer | URL
newPath:string | Buffer | URL
callback:Function
err:Error

Creates a new link from the existingPath to the newPath. See the POSIX link(2) documentation for more detail. No arguments other than a possible exception are given to the completion callback.

fs.lstat(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:Object
bigint?:boolean
Whether the numeric values in the returned fs.Stats object should be bigint. Default: false.
signal?:AbortSignal
An AbortSignal to cancel the operation. Default: undefined.
callback:Function
err:Error
stats:fs.Stats

Retrieves the fs.Stats for the symbolic link referred to by the path. The callback gets two arguments (err, stats) where stats is a fs.Stats object. lstat() is identical to stat(), except that if path is a symbolic link, then the link itself is stat-ed, not the file that it refers to.

See the POSIX lstat(2) documentation for more details.

fs.mkdir(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:Object | integer
recursive?:boolean
Default: false
mode?:string | integer
Not supported on Windows. See File modes for more details. Default: 0o777.
callback:Function
err:Error
Present only if a directory is created with recursive set to true.

Asynchronously creates a directory.

The callback is given a possible exception and, if recursive is true, the first directory path created, (err[, path]). path can still be undefined when recursive is true, if no directory was created (for instance, if it was previously created).

The optional options argument can be an integer specifying mode (permission and sticky bits), or an object with a mode property and a recursive property indicating whether parent directories should be created. Calling fs.mkdir() when path is a directory that exists results in an error only when recursive is false. If recursive is false and the directory exists, an EEXIST error occurs.

import { mkdir } from 'node:fs';

// Create ./tmp/a/apple, regardless of whether ./tmp and ./tmp/a exist.
mkdir('./tmp/a/apple', { recursive: true }, (err) => {
  if (err) throw err;
});

On Windows, using fs.mkdir() on the root directory even with recursion will result in an error:

import { mkdir } from 'node:fs';

mkdir('/', { recursive: true }, (err) => {
  // => [Error: EPERM: operation not permitted, mkdir 'C:\']
});

See the POSIX mkdir(2) documentation for more details.

fs.mkdtemp(prefix, options?, callback): void
Attributes
prefix:string | Buffer | URL
options:string | Object
encoding?:string
Default: 'utf8'
callback:Function
err:Error
directory:string

Creates a unique temporary directory.

Generates six random characters to be appended behind a required prefix to create a unique temporary directory. Due to platform inconsistencies, avoid trailing X characters in prefix. Some platforms, notably the BSDs, can return more than six random characters, and replace trailing X characters in prefix with random characters.

The created directory path is passed as a string to the callback's second parameter.

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use.

import { mkdtemp } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';

mkdtemp(join(tmpdir(), 'foo-'), (err, directory) => {
  if (err) throw err;
  console.log(directory);
  // Prints: /tmp/foo-itXde2 or C:\Users\...\AppData\Local\Temp\foo-itXde2
});

The fs.mkdtemp() method will append the six randomly selected characters directly to the prefix string. For instance, given a directory /tmp, if the intention is to create a temporary directory within /tmp, the prefix must end with a trailing platform-specific path separator (require('node:path').sep).

import { tmpdir } from 'node:os';
import { mkdtemp } from 'node:fs';

// The parent directory for the new temporary directory
const tmpDir = tmpdir();

// This method is *INCORRECT*:
mkdtemp(tmpDir, (err, directory) => {
  if (err) throw err;
  console.log(directory);
  // Will print something similar to `/tmpabc123`.
  // A new temporary directory is created at the file system root
  // rather than *within* the /tmp directory.
});

// This method is *CORRECT*:
import { sep } from 'node:path';
mkdtemp(`${tmpDir}${sep}`, (err, directory) => {
  if (err) throw err;
  console.log(directory);
  // Will print something similar to `/tmp/abc123`.
  // A new temporary directory is created within
  // the /tmp directory.
});
fs.open(path, flags?, mode?, callback): void
Attributes
path:string | Buffer | URL
flags?:string | number
See support of file system flags. Default: 'r'.
mode?:string | integer
Default: 0o666 (readable and writable)
callback:Function

Asynchronous file open. See the POSIX open(2) documentation for more details.

mode sets the file mode (permission and sticky bits), but only if the file was created. On Windows, only the write permission can be manipulated; see fs.chmod().

The callback gets two arguments (err, fd).

Some characters (< > : " / \ | ? *) are reserved under Windows as documented by Naming Files, Paths, and Namespaces. Under NTFS, if the filename contains a colon, Node.js will open a file system stream, as described by this MSDN page.

Functions based on fs.open() exhibit this behavior as well: fs.writeFile(), fs.readFile(), etc.

fs.openAsBlob(path, options?): Promise
Attributes
path:string | Buffer | URL
options:Object
type:string
An optional mime type for the blob.
Returns:Promise
Fulfills with a Blob upon success.

Returns a Blob whose data is backed by the given file.

The file must not be modified after the Blob is created. Any modifications will cause reading the Blob data to fail with a DOMException error. Synchronous stat operations on the file when the Blob is created, and before each read in order to detect whether the file data has been modified on disk.

import { openAsBlob } from 'node:fs';

const blob = await openAsBlob('the.file.txt');
const ab = await blob.arrayBuffer();
blob.stream();
const { openAsBlob } = require('node:fs');

(async () => {
  const blob = await openAsBlob('the.file.txt');
  const ab = await blob.arrayBuffer();
  blob.stream();
})();
fs.opendir(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:Object
encoding?:string | null
Default: 'utf8'
bufferSize?:number
Number of directory entries that are buffered internally when reading from the directory. Higher values lead to better performance but higher memory usage. Default: 32
recursive?:boolean
Default: false
callback:Function
err:Error
dir:fs.Dir

Asynchronously open a directory. See the POSIX opendir(3) documentation for more details.

Creates an fs.Dir, which contains all further functions for reading from and cleaning up the directory.

The encoding option sets the encoding for the path while opening the directory and subsequent read operations.

fs.read(fd, buffer, offset, length, position, callback): void
Attributes
The buffer that the data will be written to.
offset:integer
The position in buffer to write the data to.
length:integer
The number of bytes to read.
position:integer | bigint | null
Specifies where to begin reading from in the file. If position is null or -1 , data will be read from the current file position, and the file position will be updated. If position is a non-negative integer, the file position will be unchanged.
callback:Function
err:Error
bytesRead:integer
buffer:Buffer

Read data from the file specified by fd.

The callback is given the three arguments, (err, bytesRead, buffer).

If the file is not modified concurrently, the end-of-file is reached when the number of bytes read is zero.

If this method is invoked as its util.promisify()ed version, it returns a promise for an Object with bytesRead and buffer properties.

The fs.read() method reads data from the file specified by the file descriptor (fd). The length argument indicates the maximum number of bytes that Node.js will attempt to read from the kernel. However, the actual number of bytes read (bytesRead) can be lower than the specified length for various reasons.

For example:

  • If the file is shorter than the specified length, bytesRead will be set to the actual number of bytes read.
  • If the file encounters EOF (End of File) before the buffer could be filled, Node.js will read all available bytes until EOF is encountered, and the bytesRead parameter in the callback will indicate the actual number of bytes read, which may be less than the specified length.
  • If the file is on a slow network filesystem or encounters any other issue during reading, bytesRead can be lower than the specified length.

Therefore, when using fs.read(), it's important to check the bytesRead value to determine how many bytes were actually read from the file. Depending on your application logic, you may need to handle cases where bytesRead is lower than the specified length, such as by wrapping the read call in a loop if you require a minimum amount of bytes.

This behavior is similar to the POSIX preadv2 function.

fs.read(fd, options?, callback): void
Attributes
options:Object
Default: Buffer.alloc(16384)
offset?:integer
Default: 0
length?:integer
Default: buffer.byteLength - offset
position?:integer | bigint | null
Default: null
callback:Function
err:Error
bytesRead:integer
buffer:Buffer

Similar to the fs.read() function, this version takes an optional options object. If no options object is specified, it will default with the above values.

M

fs.read

History
fs.read(fd, buffer, options?, callback): void
Attributes
The buffer that the data will be written to.
options:Object
offset?:integer
Default: 0
length?:integer
Default: buffer.byteLength - offset
position?:integer | bigint
Default: null
callback:Function
err:Error
bytesRead:integer
buffer:Buffer

Similar to the fs.read() function, this version takes an optional options object. If no options object is specified, it will default with the above values.

fs.readdir(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:string | Object
encoding?:string
Default: 'utf8'
withFileTypes?:boolean
Default: false
recursive?:boolean
If true, reads the contents of a directory recursively. In recursive mode, it will list all files, sub files and directories. Default: false.
callback:Function
err:Error
files:string[] | Buffer[] | fs.Dirent[]

Reads the contents of a directory. The callback gets two arguments (err, files) where files is an array of the names of the files in the directory excluding '.' and '..'.

See the POSIX readdir(3) documentation for more details.

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use for the filenames passed to the callback. If the encoding is set to 'buffer', the filenames returned will be passed as Buffer objects.

If options.withFileTypes is set to true, the files array will contain fs.Dirent objects.

M

fs.readFile

fs.readFile(path, options?, callback): void
Attributes
filename or file descriptor
options:Object | string
encoding?:string | null
Default: null
flag?:string
See support of file system flags. Default: 'r'.
allows aborting an in-progress readFile
A buffer to read into, or a function called with the file size that returns the buffer.

Asynchronously reads the entire contents of a file.

import { readFile } from 'node:fs';

readFile('/etc/passwd', (err, data) => {
  if (err) throw err;
  console.log(data);
});

The callback is passed two arguments (err, data), where data is the contents of the file.

If no encoding is specified, then the raw buffer is returned.

If buffer is provided and no encoding is specified, the returned Buffer is a view over the supplied buffer containing only the bytes read. If the supplied buffer is too small to contain the entire file, the callback is called with an error.

If options is a string, then it specifies the encoding:

import { readFile } from 'node:fs';

readFile('/etc/passwd', 'utf8', callback);

When the path is a directory, the behavior of fs.readFile() and fs.readFileSync() is platform-specific. On macOS, Linux, and Windows, an error will be returned. On FreeBSD, a representation of the directory's contents will be returned.

import { readFile } from 'node:fs';

// macOS, Linux, and Windows
readFile('<directory>', (err, data) => {
  // => [Error: EISDIR: illegal operation on a directory, read <directory>]
});

//  FreeBSD
readFile('<directory>', (err, data) => {
  // => null, <data>
});

It is possible to abort an ongoing request using an AbortSignal. If a request is aborted the callback is called with an AbortError:

import { readFile } from 'node:fs';

const controller = new AbortController();
const signal = controller.signal;
readFile(fileInfo[0].name, { signal }, (err, buf) => {
  // ...
});
// When you want to abort the request
controller.abort();

The fs.readFile() function buffers the entire file. To minimize memory costs, when possible prefer streaming via fs.createReadStream().

Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.readFile performs.

An example using the buffer option with a pre-allocated buffer:

import { Buffer } from 'node:buffer';
import { readFile } from 'node:fs';

const buf = Buffer.alloc(16384);
readFile('/path/to/file', { buffer: buf }, (err, data) => {
  if (err) throw err;
  console.log(data); // A view over `buf` containing only the bytes read
});

An example using the buffer option with a function returning a buffer:

import { Buffer } from 'node:buffer';
import { readFile } from 'node:fs';

readFile('/path/to/file', {
  buffer: (size) => Buffer.alloc(size),
}, (err, data) => {
  if (err) throw err;
  console.log(data);
});
  1. Any specified file descriptor has to support reading.
  2. If a file descriptor is specified as the path, it will not be closed automatically.
  3. The reading will begin at the current position. For example, if the file already had 'Hello World' and six bytes are read with the file descriptor, the call to fs.readFile() with the same file descriptor, would give 'World', rather than 'Hello World'.

The fs.readFile() method asynchronously reads the contents of a file into memory one chunk at a time, allowing the event loop to turn between each chunk. This allows the read operation to have less impact on other activity that may be using the underlying libuv thread pool but means that it will take longer to read a complete file into memory.

The additional read overhead can vary broadly on different systems and depends on the type of file being read. If the file type is not a regular file (a pipe for instance) and Node.js is unable to determine an actual file size, each read operation will load on 64 KiB of data. For regular files, each read will process 512 KiB of data.

For applications that require as-fast-as-possible reading of file contents, it is better to use fs.read() directly and for application code to manage reading the full contents of the file itself.

The Node.js GitHub issue #25741 provides more information and a detailed analysis on the performance of fs.readFile() for multiple file sizes in different Node.js versions.

fs.readlink(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:string | Object
encoding?:string
Default: 'utf8'
callback:Function
err:Error
linkString:string | Buffer

Reads the contents of the symbolic link referred to by path. The callback gets two arguments (err, linkString).

See the POSIX readlink(2) documentation for more details.

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use for the link path passed to the callback. If the encoding is set to 'buffer', the link path returned will be passed as a Buffer object.

fs.readv(fd, buffers, position?, callback): void
Attributes
buffers:ArrayBufferView[]
position?:integer | null
Default: null
callback:Function
err:Error
bytesRead:integer
buffers:ArrayBufferView[]

Read from a file specified by fd and write to an array of ArrayBufferViews using readv().

position is the offset from the beginning of the file from where data should be read. If typeof position !== 'number', the data will be read from the current position.

The callback will be given three arguments: err, bytesRead, and buffers. bytesRead is how many bytes were read from the file.

If this method is invoked as its util.promisify()ed version, it returns a promise for an Object with bytesRead and buffers properties.

fs.realpath(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:string | Object
encoding?:string
Default: 'utf8'
callback:Function
err:Error
resolvedPath:string | Buffer

Asynchronously computes the canonical pathname by resolving ., .., and symbolic links.

A canonical pathname is not necessarily unique. Hard links and bind mounts can expose a file system entity through many pathnames.

This function behaves like realpath(3), with some exceptions:

  1. No case conversion is performed on case-insensitive file systems.

  2. The maximum number of symbolic links is platform-independent and generally (much) higher than what the native realpath(3) implementation supports.

The callback gets two arguments (err, resolvedPath). May use process.cwd to resolve relative paths.

Only paths that can be converted to UTF8 strings are supported.

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use for the path passed to the callback. If the encoding is set to 'buffer', the path returned will be passed as a Buffer object.

If path resolves to a socket or a pipe, the function will return a system dependent name for that object.

A path that does not exist results in an ENOENT error. error.path is the absolute file path.

fs.realpath.native(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:string | Object
encoding?:string
Default: 'utf8'
callback:Function
err:Error
resolvedPath:string | Buffer

Asynchronous realpath(3).

The callback gets two arguments (err, resolvedPath).

Only paths that can be converted to UTF8 strings are supported.

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use for the path passed to the callback. If the encoding is set to 'buffer', the path returned will be passed as a Buffer object.

On Linux, when Node.js is linked against musl libc, the procfs file system must be mounted on /proc in order for this function to work. Glibc does not have this restriction.

fs.rename(oldPath, newPath, callback): void
Attributes
oldPath:string | Buffer | URL
newPath:string | Buffer | URL
callback:Function
err:Error

Asynchronously rename file at oldPath to the pathname provided as newPath. In the case that newPath already exists, it will be overwritten. If there is a directory at newPath, an error will be raised instead. No arguments other than a possible exception are given to the completion callback.

See also: rename(2).

import { rename } from 'node:fs';

rename('oldFile.txt', 'newFile.txt', (err) => {
  if (err) throw err;
  console.log('Rename complete!');
});
M

fs.rmdir

fs.rmdir(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:Object
There are currently no options exposed. There used to be options for recursive, maxBusyTries, and emfileWait but they were deprecated and removed. The options argument is still accepted for backwards compatibility but it is not used.
callback:Function
err:Error

Asynchronous rmdir(2). No arguments other than a possible exception are given to the completion callback.

Using fs.rmdir() on a file (not a directory) results in an ENOENT error on Windows and an ENOTDIR error on POSIX.

To get a behavior similar to the rm -rf Unix command, use fs.rm() with options { recursive: true, force: true }.

fs.rm(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:Object
force?:boolean
When true, exceptions will be ignored if path does not exist. Default: false.
maxRetries?:integer
If an EBUSY, EMFILE, ENFILE, ENOTEMPTY, or EPERM error is encountered, Node.js will retry the operation with a linear backoff wait of retryDelay milliseconds longer on each try. This option represents the number of retries. This option is ignored if the recursive option is not true. Default: 0.
recursive?:boolean
If true, perform a recursive removal. In recursive mode operations are retried on failure. Default: false.
retryDelay?:integer
The amount of time in milliseconds to wait between retries. This option is ignored if the recursive option is not true. Default: 100.
callback:Function
err:Error

Asynchronously removes files and directories (modeled on the standard POSIX rm utility). No arguments other than a possible exception are given to the completion callback.

fs.stat(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:Object
bigint?:boolean
Whether the numeric values in the returned fs.Stats object should be bigint. Default: false.
throwIfNoEntry?:boolean
Whether an exception will be thrown if no file system entry exists, rather than returning undefined. Default: true.
callback:Function
err:Error
stats:fs.Stats

Asynchronous stat(2). The callback gets two arguments (err, stats) where stats is an fs.Stats object.

In case of an error, the err.code will be one of Common System Errors.

fs.stat() follows symbolic links. Use fs.lstat() to look at the links themselves.

Using fs.stat() to check for the existence of a file before calling fs.open(), fs.readFile(), or fs.writeFile() is not recommended. Instead, user code should open/read/write the file directly and handle the error raised if the file is not available.

To check if a file exists without manipulating it afterwards, fs.access() is recommended.

For example, given the following directory structure:

- txtDir
-- file.txt
- app.js

The next program will check for the stats of the given paths:

import { stat } from 'node:fs';

const pathsToCheck = ['./txtDir', './txtDir/file.txt'];

for (let i = 0; i < pathsToCheck.length; i++) {
  stat(pathsToCheck[i], (err, stats) => {
    console.log(stats.isDirectory());
    console.log(stats);
  });
}

The resulting output will resemble:

true
Stats {
  dev: 16777220,
  mode: 16877,
  nlink: 3,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14214262,
  size: 96,
  blocks: 0,
  atimeMs: 1561174653071.963,
  mtimeMs: 1561174614583.3518,
  ctimeMs: 1561174626623.5366,
  birthtimeMs: 1561174126937.2893,
  atime: 2019-06-22T03:37:33.072Z,
  mtime: 2019-06-22T03:36:54.583Z,
  ctime: 2019-06-22T03:37:06.624Z,
  birthtime: 2019-06-22T03:28:46.937Z,
  atimeInstant: 2019-06-22T03:37:33.071963Z,
  mtimeInstant: 2019-06-22T03:36:54.5833518Z,
  ctimeInstant: 2019-06-22T03:37:06.6235366Z,
  birthtimeInstant: 2019-06-22T03:28:46.9372893Z
}
false
Stats {
  dev: 16777220,
  mode: 33188,
  nlink: 1,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14214074,
  size: 8,
  blocks: 8,
  atimeMs: 1561174616618.8555,
  mtimeMs: 1561174614584,
  ctimeMs: 1561174614583.8145,
  birthtimeMs: 1561174007710.7478,
  atime: 2019-06-22T03:36:56.619Z,
  mtime: 2019-06-22T03:36:54.584Z,
  ctime: 2019-06-22T03:36:54.584Z,
  birthtime: 2019-06-22T03:26:47.711Z,
  atimeInstant: 2019-06-22T03:36:56.6188555Z,
  mtimeInstant: 2019-06-22T03:36:54.584Z,
  ctimeInstant: 2019-06-22T03:36:54.5838145Z,
  birthtimeInstant: 2019-06-22T03:26:47.7107478Z
}
M

fs.statfs

History
fs.statfs(path, options?, callback): void
Attributes
path:string | Buffer | URL
options:Object
bigint?:boolean
Whether the numeric values in the returned fs.StatFs object should be bigint. Default: false.
callback:Function
err:Error
stats:fs.StatFs

Asynchronous statfs(2). Returns information about the mounted file system which contains path. The callback gets two arguments (err, stats) where stats is an fs.StatFs object.

In case of an error, the err.code will be one of Common System Errors.

fs.symlink(target, path, type?, callback): void
Attributes
target:string | Buffer | URL
path:string | Buffer | URL
type?:string | null
Default: null
callback:Function
err:Error

Creates the link called path pointing to target. No arguments other than a possible exception are given to the completion callback.

See the POSIX symlink(2) documentation for more details.

The type argument is only available on Windows and ignored on other platforms. It can be set to 'dir', 'file', or 'junction'. If the type argument is null, Node.js will autodetect target type and use 'file' or 'dir'. If the target does not exist, 'file' will be used. Windows junction points require the destination path to be absolute. When using 'junction', the target argument will automatically be normalized to absolute path. Junction points on NTFS volumes can only point to directories.

Relative targets are relative to the link's parent directory.

import { symlink } from 'node:fs';

symlink('./mew', './mewtwo', callback);

The above example creates a symbolic link mewtwo which points to mew in the same directory:

$ tree .
.
├── mew
└── mewtwo -> ./mew
fs.truncate(path, len?, callback): void
Attributes
path:string | Buffer | URL
len?:integer
Default: 0

Truncates the file. No arguments other than a possible exception are given to the completion callback. A file descriptor can also be passed as the first argument. In this case, fs.ftruncate() is called.

import { truncate } from 'node:fs';
// Assuming that 'path/file.txt' is a regular file.
truncate('path/file.txt', (err) => {
  if (err) throw err;
  console.log('path/file.txt was truncated');
});
const { truncate } = require('node:fs');
// Assuming that 'path/file.txt' is a regular file.
truncate('path/file.txt', (err) => {
  if (err) throw err;
  console.log('path/file.txt was truncated');
});

Passing a file descriptor is deprecated and may result in an error being thrown in the future.

See the POSIX truncate(2) documentation for more details.

fs.unlink(path, callback): void
Attributes
path:string | Buffer | URL
callback:Function
err:Error

Asynchronously removes a file or symbolic link. No arguments other than a possible exception are given to the completion callback.

import { unlink } from 'node:fs';
// Assuming that 'path/file.txt' is a regular file.
unlink('path/file.txt', (err) => {
  if (err) throw err;
  console.log('path/file.txt was deleted');
});

fs.unlink() will not work on a directory, empty or otherwise. To remove a directory, use fs.rmdir().

See the POSIX unlink(2) documentation for more details.

M

fs.unwatchFile

History
fs.unwatchFile(filename, listener?): void
Attributes
filename:string | Buffer | URL
listener:Function
Optional, a listener previously attached using fs.watchFile()

Stop watching for changes on filename. If listener is specified, only that particular listener is removed. Otherwise, all listeners are removed, effectively stopping watching of filename.

Calling fs.unwatchFile() with a filename that is not being watched is a no-op, not an error.

Using fs.watch() is more efficient than fs.watchFile() and fs.unwatchFile(). fs.watch() should be used instead of fs.watchFile() and fs.unwatchFile() when possible.

fs.utimes(path, atime, mtime, callback): void
Attributes
path:string | Buffer | URL
atime:number | string | Date
mtime:number | string | Date
callback:Function
err:Error

Change the file system timestamps of the object referenced by path.

The atime and mtime arguments follow these rules:

  • Values can be either numbers representing Unix epoch time in seconds, Dates, or a numeric string like '123456789.0'.
  • If the value can not be converted to a number, or is NaN, Infinity, or -Infinity, an Error will be thrown.
fs.watch(filename, options?, listener?): fs.FSWatcher
Attributes
filename:string | Buffer | URL
options:string | Object
persistent?:boolean
Indicates whether the process should continue to run as long as files are being watched. Default: true.
recursive?:boolean
Indicates whether all subdirectories should be watched, or only the current directory. This applies when a directory is specified, and only on supported platforms (See caveats). Default: false.
encoding?:string
Specifies the character encoding to be used for the filename passed to the listener. Default: 'utf8'.
allows closing the watcher with an AbortSignal.
throwIfNoEntry?:boolean
Indicates whether an exception should be thrown when the path does not exist. Default: true.
ignore?:string | RegExp | Function | Array
Pattern(s) to ignore. Strings are glob patterns (using minimatch), RegExp patterns are tested against the filename, and functions receive the filename and return true to ignore. Default: undefined.
listener?:Function | undefined
Default: undefined
eventType:string
filename:string | Buffer | null
Returns:fs.FSWatcher

Watch for changes on filename, where filename is either a file or a directory.

The second argument is optional. If options is provided as a string, it specifies the encoding. Otherwise options should be passed as an object.

The listener callback gets two arguments (eventType, filename). eventType is either 'rename' or 'change', and filename is the name of the file which triggered the event.

On most platforms, 'rename' is emitted whenever a filename appears or disappears in the directory.

The listener callback is attached to the 'change' event fired by fs.FSWatcher, but it is not the same thing as the 'change' value of eventType.

If a signal is passed, aborting the corresponding AbortController will close the returned fs.FSWatcher.

The fs.watch API is not 100% consistent across platforms, and is unavailable in some situations.

On Windows, no events will be emitted if the watched directory is moved or renamed. An EPERM error is reported when the watched directory is deleted.

The fs.watch API does not provide any protection with respect to malicious actions on the file system. For example, on Windows it is implemented by monitoring changes in a directory versus specific files. This allows substitution of a file and fs reporting changes on the new file with the same filename.

This feature depends on the underlying operating system providing a way to be notified of file system changes.

  • On Linux systems, this uses inotify(7).
  • On BSD systems, this uses kqueue(2).
  • On macOS, this uses kqueue(2) for files and FSEvents for directories.
  • On SunOS systems (including Solaris and SmartOS), this uses event ports.
  • On Windows systems, this feature depends on ReadDirectoryChangesW.
  • On AIX systems, this feature depends on AHAFS, which must be enabled.
  • On IBM i systems, this feature is not supported.

If the underlying functionality is not available for some reason, then fs.watch() will not be able to function and may throw an exception. For example, watching files or directories can be unreliable, and in some cases impossible, on network file systems (NFS, SMB, etc) or host file systems when using virtualization software such as Vagrant or Docker.

It is still possible to use fs.watchFile(), which uses stat polling, but this method is slower and less reliable.

On Linux and macOS systems, fs.watch() resolves the path to an inode and watches the inode. If the watched path is deleted and recreated, it is assigned a new inode. The watch will emit an event for the delete but will continue watching the original inode. Events for the new inode will not be emitted. This is expected behavior.

AIX files retain the same inode for the lifetime of a file. Saving and closing a watched file on AIX will result in two notifications (one for adding new content, and one for truncation).

Providing filename argument in the callback is only supported on Linux, macOS, Windows, and AIX. Even on supported platforms, filename is not always guaranteed to be provided. Therefore, don't assume that filename argument is always provided in the callback, and have some fallback logic if it is null.

import { watch } from 'node:fs';
watch('somedir', (eventType, filename) => {
  console.log(`event type is: ${eventType}`);
  if (filename) {
    console.log(`filename provided: ${filename}`);
  } else {
    console.log('filename not provided');
  }
});
fs.watchFile(filename, options?, listener): fs.StatWatcher
Attributes
filename:string | Buffer | URL
options:Object
bigint?:boolean
Default: false
persistent?:boolean
Default: true
interval?:integer
Default: 5007
listener:Function
current:fs.Stats
previous:fs.Stats

Watch for changes on filename. The callback listener will be called each time the file is accessed.

The options argument may be omitted. If provided, it should be an object. The options object may contain a boolean named persistent that indicates whether the process should continue to run as long as files are being watched. The options object may specify an interval property indicating how often the target should be polled in milliseconds.

The listener gets two arguments the current stat object and the previous stat object:

import { watchFile } from 'node:fs';

watchFile('message.text', (curr, prev) => {
  console.log(`the current mtime is: ${curr.mtime}`);
  console.log(`the previous mtime was: ${prev.mtime}`);
});

These stat objects are instances of fs.Stat. If the bigint option is true, the numeric values in these objects are specified as BigInts.

To be notified when the file was modified, not just accessed, it is necessary to compare curr.mtimeMs and prev.mtimeMs.

When an fs.watchFile operation results in an ENOENT error, it will invoke the listener once, with all the fields zeroed (or, for dates, the Unix Epoch). If the file is created later on, the listener will be called again, with the latest stat objects. This is a change in functionality since v0.10.

Using fs.watch() is more efficient than fs.watchFile and fs.unwatchFile. fs.watch should be used instead of fs.watchFile and fs.unwatchFile when possible.

When a file being watched by fs.watchFile() disappears and reappears, then the contents of previous in the second callback event (the file's reappearance) will be the same as the contents of previous in the first callback event (its disappearance).

This happens when:

  • the file is deleted, followed by a restore
  • the file is renamed and then renamed a second time back to its original name
fs.write(fd, buffer, offset?, length?, position?, callback): void
Attributes
offset?:integer
Default: 0
length?:integer
Default: buffer.byteLength - offset
position?:integer | null
Default: null
callback:Function
err:Error
bytesWritten:integer

Write buffer to the file specified by fd.

offset determines the part of the buffer to be written, and length is an integer specifying the number of bytes to write.

position refers to the offset from the beginning of the file where this data should be written. If typeof position !== 'number', the data will be written at the current position. See pwrite(2).

The callback will be given three arguments (err, bytesWritten, buffer) where bytesWritten specifies how many bytes were written from buffer.

If this method is invoked as its util.promisify()ed version, it returns a promise for an Object with bytesWritten and buffer properties.

It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended.

On Linux, positional writes don't work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file.

M

fs.write

History
fs.write(fd, buffer, options?, callback): void
Attributes
options:Object
offset?:integer
Default: 0
length?:integer
Default: buffer.byteLength - offset
position?:integer | null
Default: null
callback:Function
err:Error
bytesWritten:integer

Write buffer to the file specified by fd.

Similar to the above fs.write function, this version takes an optional options object. If no options object is specified, it will default with the above values.

fs.write(fd, string, position?, encoding?, callback): void
Attributes
string:string
position?:integer | null
Default: null
encoding?:string
Default: 'utf8'
callback:Function
err:Error
written:integer
string:string

Write string to the file specified by fd. If string is not a string, an exception is thrown.

position refers to the offset from the beginning of the file where this data should be written. If typeof position !== 'number' the data will be written at the current position. See pwrite(2).

encoding is the expected string encoding.

The callback will receive the arguments (err, written, string) where written specifies how many bytes the passed string required to be written. Bytes written is not necessarily the same as string characters written. See Buffer.byteLength.

It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended.

On Linux, positional writes don't work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file.

On Windows, if the file descriptor is connected to the console (e.g. fd == 1 or stdout) a string containing non-ASCII characters will not be rendered properly by default, regardless of the encoding used. It is possible to configure the console to render UTF-8 properly by changing the active codepage with the chcp 65001 command. See the chcp docs for more details.

M

fs.writeFile

fs.writeFile(file, data, options?, callback): void
Attributes
filename or file descriptor
options:Object | string
encoding?:string | null
Default: 'utf8'
mode?:integer
Default: 0o666
flag?:string
See support of file system flags. Default: 'w'.
flush?:boolean
If all data is successfully written to the file, and flush is true, fs.fsync() is used to flush the data. Default: false.
allows aborting an in-progress writeFile

When file is a filename, asynchronously writes data to the file, replacing the file if it already exists. data can be a string or a buffer.

When file is a file descriptor, the behavior is similar to calling fs.write() directly (which is recommended). See the notes below on using a file descriptor.

The encoding option is ignored if data is a buffer.

The mode option only affects the newly created file. See fs.open() for more details.

import { writeFile } from 'node:fs';
import { Buffer } from 'node:buffer';

const data = new Uint8Array(Buffer.from('Hello Node.js'));
writeFile('message.txt', data, (err) => {
  if (err) throw err;
  console.log('The file has been saved!');
});

If options is a string, then it specifies the encoding:

import { writeFile } from 'node:fs';

writeFile('message.txt', 'Hello Node.js', 'utf8', callback);

It is unsafe to use fs.writeFile() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended.

Similarly to fs.readFile - fs.writeFile is a convenience method that performs multiple write calls internally to write the buffer passed to it. For performance sensitive code consider using fs.createWriteStream().

It is possible to use an AbortSignal to cancel an fs.writeFile(). Cancelation is "best effort", and some amount of data is likely still to be written.

import { writeFile } from 'node:fs';
import { Buffer } from 'node:buffer';

const controller = new AbortController();
const { signal } = controller;
const data = new Uint8Array(Buffer.from('Hello Node.js'));
writeFile('message.txt', data, { signal }, (err) => {
  // When a request is aborted - the callback is called with an AbortError
});
// When the request should be aborted
controller.abort();

Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.writeFile performs.

When file is a file descriptor, the behavior is almost identical to directly calling fs.write() like:

import { write } from 'node:fs';
import { Buffer } from 'node:buffer';

write(fd, Buffer.from(data, options.encoding), callback);

The difference from directly calling fs.write() is that under some unusual conditions, fs.write() might write only part of the buffer and need to be retried to write the remaining data, whereas fs.writeFile() retries until the data is entirely written (or an error occurs).

The implications of this are a common source of confusion. In the file descriptor case, the file is not replaced! The data is not necessarily written to the beginning of the file, and the file's original data may remain before and/or after the newly written data.

For example, if fs.writeFile() is called twice in a row, first to write the string 'Hello', then to write the string ', World', the file would contain 'Hello, World', and might contain some of the file's original data (depending on the size of the original file, and the position of the file descriptor). If a file name had been used instead of a descriptor, the file would be guaranteed to contain only ', World'.

fs.writev(fd, buffers, position?, callback): void
Attributes
buffers:ArrayBufferView[]
position?:integer | null
Default: null
callback:Function
err:Error
bytesWritten:integer
buffers:ArrayBufferView[]

Write an array of ArrayBufferViews to the file specified by fd using writev().

position is the offset from the beginning of the file where this data should be written. If typeof position !== 'number', the data will be written at the current position.

The callback will be given three arguments: err, bytesWritten, and buffers. bytesWritten is how many bytes were written from buffers.

If this method is util.promisify()ed, it returns a promise for an Object with bytesWritten and buffers properties.

It is unsafe to use fs.writev() multiple times on the same file without waiting for the callback. For this scenario, use fs.createWriteStream().

On Linux, positional writes don't work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file.