A few months ago, I saw somebody on Twitter ask how to asynchronously check if a file exists in Node.js. This used to be possible with the fs.exists() method which is now deprecated. The synchronous fs.existsSync() method is still available, but what if you need the async version?

The fs.access() method

The fs.access() method tests a user's permissions for a file or directory. It accepts up to three arguments:

  1. The path to the file or directory.
  2. The check to perform (see File access constants).
  3. A callback function with a possible error argument.

Here's how you can use the access() method to check if a file exists in the current directory. The code is available as a gist.

We want to check if the file exists, so we need to use the F_OK constant as our second argument. This flag indicates that the file is visible to the calling process. The R_OK and W_OK constants are flags which indicate that the file can be read and written.

Callback API

import { access, constants } from 'fs';

const file = 'package.json';

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

Promises API

The fsPromises.access() method returns a promise that fulfills with undefined upon success. This means we don't need to specify a parameter for our callback to the then() method.

import { constants } from 'fs';
import { access } from 'fs/promises';

const file = 'package.json';

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

Warning

You should only use the access() method to check if a file exists without manipulating it afterwards. You shouldn't use it if you need to actually work with the file itself. The Node.js docs explain why, and offer an alternative:

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.

Next week, we'll look at the proper way to do it.