How to check if file exists in Node.js

May 12, 2023#node#how-to

Checking the existence of a file is a common task in Node.js applications. Whether you need to verify if a file exists before performing an operation or simply want to handle different scenarios based on file availability, Node.js provides several approaches to accomplish this task using the file system module (fs) with synchronous, callback, or promise based APIs:

Using "exists" methods

fs.exists(path, callback)
fs.existsSync(path)

Using fs.existsSync() to synchronously check if a file or directory exists. This method returns a boolean value and does not throw an error if the path does not exist. However, it is not recommended to use this method in most cases, as it can introduce race conditions and block the event loop.

const fs = require("fs");
if (fs.existsSync("foo.txt")) {
  // Do something
}

Method fs.exists() is deprecated, but fs.existsSync() is not. 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().

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

Using "access" methods

fs.promises.access(path[, mode])
fs.access(path[, mode], callback)
fs.accessSync(path[, mode])

Using “access” methods to check if a file or directory exists and if you have the permissions to access it. These methods take a callback or return a promise, respectively, and do not throw an error if the path does not exist. Instead, they pass an error object to the callback or reject the promise. You can use the constant fs.constants.F_OK as the mode argument to check for the existence of the file.

const fs = require("fs");
fs.access("foo.txt", fs.constants.F_OK, (err) => {
  if (!err) {
    // Do something
  }
});

(async () => {
  try {
    await fs.promises.access("foo.txt", fs.constants.F_OK);
    // Do something
  } catch (err) {
    // Handle error
  }
})();

Using "stat" methods

fs.promises.stat(path[, options])
fs.stat(path[, options], callback)
fs.statSync(path[, options])

fs.promises.lstat(path[, options])
fs.lstat(path[, options], callback)
fs.lstatSync(path[, options])

Using “stat” methods gets the file status and invokes the callback with an error argument if the file does not exist, “stat” resolves symbolic links and returns information about the target file or directory, while “lstat” does not follow symbolic links and returns information about the link itself.

const fs = require("fs");

fs.stat("foo.txt", (err, stat) => {
  if (!err) {
    // Do something
  }
});

fs.lstat("foo.txt", (err, stats) => {
  if (err) {
    // Handle the error, as the file might not exist or there was a problem accessing it
    console.error(err);
    return;
  }

  // Process the file information
  if (stats.isFile()) {
    console.log('The path is a file.');
  } else if (stats.isDirectory()) {
    console.log('The path is a directory.');
  } else if (stats.isSymbolicLink()) {
    console.log('The path is a symbolic link.');
  }

  // You can access other properties such as size, permissions, etc.
  console.log('Size:', stats.size);
});

Using file methods

fs.promises.open(path, flags[, mode])
fs.open(path[, flags[, mode]], callback)
fs.openSync(path[, flags[, mode]])

fs.promises.readFile(path[, options])
fs.readFile(path[, options], callback)
fs.readFileSync(path[, options])

fs.promises.writeFile(file, data[, options])
fs.writeFile(file, data[, options], callback)
fs.writeFileSync(file, data[, options])

You can use fs.open() or fs.readFile() to asynchronously open or read a file, and handle the error if it does not exist. This is recommended if you intend to use the file after checking its existence, as it avoids race conditions and reduces the number of system calls.

const fs = require("fs");

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

    throw err;
  }

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

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.