406

How do I check for the existence of a file?

4
  • 8
    As of 2018, use fs.access('file', err => err ? 'does not exist' : 'exists'), see fs.access Commented Jan 12, 2019 at 16:59
  • 1
    Indeed. Node.js docs recommend against using fs.access() (elsewhere recommended on this page) to check file access without the follow-up intention to also read/manipulate the file. Commented Feb 1, 2023 at 13:46
  • @Mitya Yes but only if you plan to access the file with open, readFile, or WriteFile. Those methods' have their own error handling that should be used. It also creates a race condition. Commented Nov 15, 2023 at 13:18
  • As of 2025, I think my answer is the only one that is both comprehensive and recommended. That's because -- unfortunately -- the answer changes every few years; there isn't one answer to this question anymore. BTW, I recommend against fs.access() due to portability concerns: "The fs.access() function ... may report that a path is accessible even if the [Windows] ACL restricts the user from reading or writing to it" Commented Jun 14 at 21:19

27 Answers 27

492

Consider opening or reading the file directly, to avoid race conditions:

const fs = require('fs');

fs.open('foo.txt', 'r', (err, fd) => {
  // ...
});
fs.readFile('foo.txt', (err, data) => {
  if (!err && data) {
    // ...
  }
})

Using fs.existsSync:

if (fs.existsSync('foo.txt')) {
  // ...
}

Using fs.stat:

fs.stat('foo.txt', function(err, stat) {
  if (err == null) {
    console.log('File exists');
  } else if (err.code === 'ENOENT') {
    // file does not exist
    fs.writeFile('log.txt', 'Some log\n');
  } else {
    console.log('Some other error: ', err.code);
  }
});

Deprecated:

fs.exists is deprecated.

Using path.exists:

const path = require('path');

path.exists('foo.txt', function(exists) { 
  if (exists) { 
    // ...
  } 
});

Using path.existsSync:

if (path.existsSync('foo.txt')) { 
  // ...
}
Sign up to request clarification or add additional context in comments.

12 Comments

path.exists actually is deprecated in favor of fs.exists
Anyone reading this now (Node.js v0.12.x) keep in mind that fs.exists and fs.existsSync have also been deprecated. The best way to check file existence is fs.stat, as demoed above.
From Node js documentation, seems like the best way to go if you plan on opening the file after checking its existence, is to actually open it and handle the errors if it doesn't exists. Because your file could be removed between your exists check and the open function...
@Antrikshy fs.existsSync is no longer depricated, though fs.exists still is.
pls remove the 1st part of the answer, which works only for node < 0.12 (way too old)
|
206

Edit: Since node v10.0.0we could use fs.promises.access(...)

Example async code that checks if file exists:

function checkFileExists(file) {
  return fs.promises.access(file, fs.constants.F_OK)
           .then(() => true)
           .catch(() => false)
}

An alternative for stat might be using the new fs.access(...):

minified short promise function for checking:

s => new Promise(r=>fs.access(s, fs.constants.F_OK, e => r(!e)))

Sample usage:

let checkFileExists = s => new Promise(r=>fs.access(s, fs.constants.F_OK, e => r(!e)))
checkFileExists("Some File Location")
  .then(bool => console.log(´file exists: ${bool}´))

expanded Promise way:

// returns a promise which resolves true if file exists:
function checkFileExists(filepath){
  return new Promise((resolve, reject) => {
    fs.access(filepath, fs.constants.F_OK, error => {
      resolve(!error);
    });
  });
}

or if you wanna do it synchronously:

function checkFileExistsSync(filepath){
  let flag = true;
  try{
    fs.accessSync(filepath, fs.constants.F_OK);
  }catch(e){
    flag = false;
  }
  return flag;
}

7 Comments

Upvoted, this is definitely the most modern (2018) way to detect if a file exists in Node.js
Yes this is the official recommended method to simply check if the file exists and manipulation afterwards is not expected. Otherwise use open/write/read and handle the error. nodejs.org/api/fs.html#fs_fs_stat_path_callback
In the documentation I find fs.constants.F_OK etc. Is it also possible to access them like fs.F_OK? Weird. Also terse, which is nice.
Could try doing it with fs.promises.access(path, fs.constants.F_OK); to simply make it a Promise instead of creating a Promise.
This code is so ugly compared to the simple fs.exists one...really wonder why they force us to use such alternatives :'-(
|
99

A easier way to do this synchronously.

if (fs.existsSync('/etc/file')) {
    console.log('Found file');
}

The API doc says how existsSync work:
Test whether or not the given path exists by checking with the file system.

9 Comments

@Imeurs but nodejs.org/api/fs.html#fs_fs_existssync_path say: Note that fs.exists() is deprecated, but fs.existsSync() is not.
fs.existsSync was deprecated, but it no longer is.
Synchronous is "easier", but it's also categorically worse because you block the whole process waiting for I/O and other tasks can't make progress. Embrace promises and asynchrony, which the app probably has to use anyway if it's nontrivial.
Synchronous or not will not make any difference to the performance of an exists() function. Under the covers it will call a C function like stat and yield a boolean. It's not like other async IO or timer where it may yield or make partial progress. However because exists() is ephemeral the caller has to be careful mixing sync and async, using either chaining promises with .then() or using the await keyword to ensure proper ordering so there aren't inadvertent race conditions.
@locka It's still a system call, which is out of process, therefore async. You're blocking the Node thread waiting for a system call to get back to you. This is acceptable in simple command line scripts, but not good in a web server where performance relies on not blocking the event loop as much as possible.
|
57

Modern async/await way ( Node 12.8.x )

const fileExists = async path => !!(await fs.promises.stat(path).catch(e => false));

const main = async () => {
    console.log(await fileExists('/path/myfile.txt'));
}

main();

We need to use fs.stat() or fs.access() because fs.exists(path, callback) now is deprecated

Another good way is fs-extra

2 Comments

A couple characters shorter and maybe easier to read: const fileExists = path => fs.promises.stat(path).then(() => true, () => false);
If you import fs with const fs = require("node:fs/promises"): then you can remove .promises from the code too.
25

A concise solution in async await style:

import { stat } from 'fs/promises';

const exists = await stat('foo.txt')
   .then(() => true)
   .catch(() => false);

3 Comments

If you are going to do await, then do try/catch too...
Because we we want to exsits to be a boolean. and we don't want to get an ecception thrown if the file dosen't exsist.
Isn't await with then/catch kind of pointless?
21

fs.exists(path, callback) and fs.existsSync(path) are deprecated now, see https://nodejs.org/api/fs.html#fs_fs_exists_path_callback and https://nodejs.org/api/fs.html#fs_fs_existssync_path.

To test the existence of a file synchronously one can use ie. fs.statSync(path). An fs.Stats object will be returned if the file exists, see https://nodejs.org/api/fs.html#fs_class_fs_stats, otherwise an error is thrown which will be catched by the try / catch statement.

var fs = require('fs'),
  path = '/path/to/my/file',
  stats;

try {
  stats = fs.statSync(path);
  console.log("File exists.");
}
catch (e) {
  console.log("File does not exist.");
}

4 Comments

The link you provided for fs.existsync clearly stats that it is NOT deprecated "Note that fs.exists() is deprecated, but fs.existsSync() is not. (The callback parameter to fs.exists() accepts parameters that are inconsistent with other Node.js callbacks. fs.existsSync() does not use a callback.)"
the first (from the top) answer, which mentioned where the fs variable comes from
At the time this answer was written, the info was correct; however, fs.existsSync() is no longer deprecated.
I'm sorry, but what does say that "existsSync" is deprecated exactly?
21

Aug 2021

After reading all posts:

let filePath = "./directory1/file1.txt";

if (fs.existsSync(filePath)) {
    console.log("The file exists");
} else {
    console.log("The file does not exist");
}

1 Comment

According to the documentation: "fs.exists() is deprecated, but fs.existsSync() is not. The callback parameter to fs.exists() accepts parameters that are inconsistent with other Node.js callbacks. fs.existsSync() does not use a callback."
15

Old Version before V6: here's the documentation

  const fs = require('fs');    
  fs.exists('/etc/passwd', (exists) => {
     console.log(exists ? 'it\'s there' : 'no passwd!');
  });
// or Sync

  if (fs.existsSync('/etc/passwd')) {
    console.log('it\'s there');
  }

UPDATE

New versions from V6: documentation for fs.stat

fs.stat('/etc/passwd', function(err, stat) {
    if(err == null) {
        //Exist
    } else if(err.code == 'ENOENT') {
        // NO exist
    } 
});

2 Comments

Both fs.exists and fs.existsSync are deprecated according to the link you shared.
existsSync is not deprecated as per that doc, may be it was when you read it.
12

There are a lot of inaccurate comments about fs.existsSync() being deprecated; it is not.

https://nodejs.org/api/fs.html#fs_fs_existssync_path

Note that fs.exists() is deprecated, but fs.existsSync() is not.

Comments

9

@Fox: great answer! Here's a bit of an extension with some more options. It's what I've been using lately as a go-to solution:

var fs = require('fs');

fs.lstat( targetPath, function (err, inodeStatus) {
  if (err) {

    // file does not exist-
    if (err.code === 'ENOENT' ) {
      console.log('No file or directory at',targetPath);
      return;
    }

    // miscellaneous error (e.g. permissions)
    console.error(err);
    return;
  }


  // Check if this is a file or directory
  var isDirectory = inodeStatus.isDirectory();


  // Get file size
  //
  // NOTE: this won't work recursively for directories-- see:
  // http://stackoverflow.com/a/7550430/486547
  //
  var sizeInBytes = inodeStatus.size;

  console.log(
    (isDirectory ? 'Folder' : 'File'),
    'at',targetPath,
    'is',sizeInBytes,'bytes.'
  );


}

P.S. check out fs-extra if you aren't already using it-- it's pretty sweet. https://github.com/jprichardson/node-fs-extra)

Comments

9

Simple one-liner with Node.js fs/promises

import fs from 'node:fs/promises';

let exists = await fs.access('file.txt').then(() => true).catch(() => false);

exists will be true if the file exists, or false if it doesn't.

See also:

Comments

8

fs.exists has been deprecated since 1.0.0. You can use fs.stat instead of that.

var fs = require('fs');
fs.stat(path, (err, stats) => {
if ( !stats.isFile(filename) ) { // do this 
}  
else { // do this 
}});

Here is the link for the documentation fs.stats

1 Comment

stats.isFile() does not need filename.
7

For those who ❤️ async-await

import fsp from 'fs/promises';

async function doesFileExist(path) {
    try {
        return (await fsp.stat(path)).isFile();
    } catch (e) {
        return false;
    }
}

const path = './dir/file.pdf';
console.log(await doesFileExist(path));

Comments

3

async/await version using util.promisify as of Node 8:

const fs = require('fs');
const { promisify } = require('util');
const stat = promisify(fs.stat);

describe('async stat', () => {
  it('should not throw if file does exist', async () => {
    try {
      const stats = await stat(path.join('path', 'to', 'existingfile.txt'));
      assert.notEqual(stats, null);
    } catch (err) {
      // shouldn't happen
    }
  });
});

describe('async stat', () => {
  it('should throw if file does not exist', async () => {
    try {
      const stats = await stat(path.join('path', 'to', 'not', 'existingfile.txt'));
    } catch (err) {
      assert.notEqual(err, null);
    }
  });
});

1 Comment

No more need for promisify if you use const fs = require("node:fs/promises").
2

For asynchronous version! And with the promise version! Here the clean simple way!

try {
    await fsPromise.stat(filePath);
    /**
     * File exists!
     */
    // do something
} catch (err) {
    if (err.code = 'ENOENT') {
        /**
        * File not found
        */
    } else {
        // Another error!
    }
}

A more practical snippet from my code to illustrate better:


try {
    const filePath = path.join(FILES_DIR, fileName);
    await fsPromise.stat(filePath);
    /**
     * File exists!
     */
    const readStream = fs.createReadStream(
        filePath,
        {
            autoClose: true,
            start: 0
        }
    );

    return {
        success: true,
        readStream
    };
} catch (err) {
    /**
     * Mapped file doesn't exists
     */
    if (err.code = 'ENOENT') {
        return {
            err: {
                msg: 'Mapped file doesn\'t exists',
                code: EErrorCode.MappedFileNotFound
            }
        };
    } else {
        return {
            err: {
                msg: 'Mapped file failed to load! File system error',
                code: EErrorCode.MappedFileFileSystemError
            }
        }; 
   }
}

The example above is just for demonstration! I could have used the error event of the read stream! To catch any errors! And skip the two calls!

Comments

2

I hate to add another similar answer to an already-bloated thread, but here's the shortest (but still readable) async version I know of at the time of writing, following up on this comment:

const fs = require("node:fs/promises");

const fileExists = path => fs.stat(path).then(() => true, () => false);

// usage:
(async () => {
  const filename = "foo.txt";

  if (await fileExists(filename)) {
    console.log(filename, "exists");
  } else {
    console.log(filename, "does not exist");
  }
})();

.then's second argument works like .catch.

Comments

1

Well I did it this way, as seen on https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback

fs.access('./settings', fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK, function(err){
  console.log(err ? 'no access or dir doesnt exist' : 'R/W ok');

  if(err && err.code === 'ENOENT'){
    fs.mkdir('settings');
  }
});

Is there any problem with this?

Comments

1
  fs.statSync(path, function(err, stat){
      if(err == null) {
          console.log('File exists');
          //code when all ok
      }else if (err.code == "ENOENT") {
        //file doesn't exist
        console.log('not file');

      }
      else {
        console.log('Some other error: ', err.code);
      }
    });

Comments

1

After a bit of experimentation, I found the following example using fs.stat to be a good way to asynchronously check whether a file exists. It also checks that your "file" is "really-is-a-file" (and not a directory).

This method uses Promises, assuming that you are working with an asynchronous codebase:

const fileExists = path => {
  return new Promise((resolve, reject) => {
    try {
      fs.stat(path, (error, file) => {
        if (!error && file.isFile()) {
          return resolve(true);
        }

        if (error && error.code === 'ENOENT') {
          return resolve(false);
        }
      });
    } catch (err) {
      reject(err);
    }
  });
};

If the file does not exist, the promise still resolves, albeit false. If the file does exist, and it is a directory, then is resolves true. Any errors attempting to read the file will reject the promise the error itself.

3 Comments

No more need for promisify if you use const fs = require("node:fs/promises"), or even built in promisification which would be better than trying to roll it yourself.
@ggorlen, why would built in promisification be better than building it yourself, technically? It's doing the same thing, no? Are you just talking about code readability? I ask because back when I learned promises, libraries didn't have them built in, so I just learned to create them myself, and found I really enjoyed writing my own promises. (I answered this question almost 8 years ago.)
The reasons not to roll it yourself when it's in the standard library should be obvious: you might mess something up, it's less code to maintain and check in, easier to read, eliminates potential bugs, etc. You can delete or update your answer--it's no longer helpful to future visitors, sorry to say.
1

Using typescript and fs/promises in node14

import * as fsp from 'fs/promises';
try{
const = await fsp.readFile(fullFileName)
...
} catch(e) { ...}

It is better to use fsp.readFile than fsp.stator fsp.access for two reasons:

  1. The least important reason - it is one less access.
  2. It is possible that fsp.statand fsp.readFile would give different answers. Either due to subtle differences in the questions they ask, or because the files status changed between the calls. So the coder would have to code for two conditional branches instead of one, and the user might see more behaviors.

Comments

1

came across this thread, and it seems many fail to mention the following / cleaner async approach:

since Node v15.3.0, v14.17.0, fs.statSync Accepts a throwIfNoEntry option to specify whether an exception should be thrown if the entry does not exist:

function isDirectory (path) {
  return fs.statSync(path, { throwIfNoEntry: false })?.isDirectory() ?? false
}

function isFile (path) {
  return fs.statSync(path, { throwIfNoEntry: false })?.isFile() ?? false
}

details:

fs.statSync(path, { throwIfNoEntry: false }): Retrieves the <fs.Stats> for the path.

?.isFile(): optional chaining call to isFile() or isDirectory() to avoid TypeError: Cannot read properties of undefined error.

?? false use nullish coalescing operator to return false in the previous case where the left side is undefined

Comments

0

in old days before sit down I always check if chair is there then I sit else I have an alternative plan like sit on a coach. Now node.js site suggest just go (no needs to check) and the answer looks like this:

    fs.readFile( '/foo.txt', function( err, data )
    {
      if(err) 
      {
        if( err.code === 'ENOENT' )
        {
            console.log( 'File Doesn\'t Exist' );
            return;
        }
        if( err.code === 'EACCES' )
        {
            console.log( 'No Permission' );
            return;
        }       
        console.log( 'Unknown Error' );
        return;
      }
      console.log( data );
    } );

code taken from http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/ from March 2014, and slightly modified to fit computer. It checks for permission as well - remove permission for to test chmod a-r foo.txt

Comments

0

You can use fs.stat to check if target is a file or directory and you can use fs.access to check if you can write/read/execute the file. (remember to use path.resolve to get full path for the target)

Documentation:

Full example (TypeScript)

import * as fs from 'fs';
import * as path from 'path';

const targetPath = path.resolve(process.argv[2]);

function statExists(checkPath): Promise<fs.Stats> {
  return new Promise((resolve) => {
    fs.stat(checkPath, (err, result) => {
      if (err) {
        return resolve(undefined);
      }

      return resolve(result);
    });
  });
}

function checkAccess(checkPath: string, mode: number = fs.constants.F_OK): Promise<boolean> {
  return new Promise((resolve) => {
    fs.access(checkPath, mode, (err) => {
      resolve(!err);
    });
  });
}

(async function () {
  const result = await statExists(targetPath);
  const accessResult = await checkAccess(targetPath, fs.constants.F_OK);
  const readResult = await checkAccess(targetPath, fs.constants.R_OK);
  const writeResult = await checkAccess(targetPath, fs.constants.W_OK);
  const executeResult = await checkAccess(targetPath, fs.constants.X_OK);
  const allAccessResult = await checkAccess(targetPath, fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK | fs.constants.X_OK);

  if (result) {
    console.group('stat');
    console.log('isFile: ', result.isFile());
    console.log('isDir: ', result.isDirectory());
    console.groupEnd();
  }
  else {
    console.log('file/dir does not exist');
  }

  console.group('access');
  console.log('access:', accessResult);
  console.log('read access:', readResult);
  console.log('write access:', writeResult);
  console.log('execute access:', executeResult);
  console.log('all (combined) access:', allAccessResult);
  console.groupEnd();

  process.exit(0);
}());

Comments

0

If you want to use fs.access as suggested multiple times, don't forget to check for ENOENT, otherwise any error accessing the file also counts towards the file not being found:

async function exists(path) {
  try {
    await fs.access(path);
    return true;
  } catch (err) {
    if (err.code === 'ENOENT') {
      return false;
    } else {
      throw err;
    }
  }
}

Or as a const / inline function:

const exists = path => fs.access(path).then(() => true, err => {
  if (err.code === 'ENOENT') { // "file or directory does not exist"
      return false;
  } else {
      throw err;
  }
});

Comments

0

2025 answer

Unfortunately, this answer changes every few years. Today, it's 2025, Node.js v24 is current, and the answer to this question depends on your situation:

Will modify file if check passes Won't modify file if check passes
Synchronous? fs.existsSync fs.existsSync
Asynchronous? fsPromises.open / fsPromises.readFile / fsPromises.writeFile and handle the error raised if the file is not accessible fsPromises.access

The following examples will show you how to use these functions. Assume that missing.txt does not exist in the file system, and exists.txt does exist.

fs.existsSync example

import fs as 'fs';

console.log(fs.existsSync('missing.txt')); // Output: false
console.log(fs.existsSync('exists.txt')); // Output: true

fsPromises.access example

import fs from 'fs/promises';

try {
  await fs.access('missing.txt');
  console.log(`Unexpected! Should not log`);
} catch (err) {
  console.log(`Expected! File does not exist`, err);
}
// Output: Expected! File does not exist Error: ENOENT: no such file or directory, access ...


try {
  await fs.access('exists.txt')
  console.log(`Expected! File does exist`);
} catch (err) {
  console.log(`Unexpected! Should not log`, err);
}
// Output: Expected! File does exist

fsPromises.open example

try {
  await fs.open('missing.txt');
  console.log(`Unexpected! Should not log`);
} catch (err) {
  console.log(`Expected! File does not exist`, err);
}
// Output: Expected! File does not exist Error: ENOENT: no such file or directory, open ...


try {
  await fs.open('exists.txt')
  console.log(`Expected! File does exist`);
} catch (err) {
  console.log(`Unexpected! Should not log`, err);
}
// Output: Expected! File does exist

fsPromises.readFile example

try {
  await fs.readFile('missing.txt');
  console.log(`Unexpected! Should not log`);
} catch (err) {
  console.log(`Expected! File does not exist`, err);
}
// Output: Expected! File does not exist Error: ENOENT: no such file or directory, open ...


try {
  await fs.readFile('exists.txt')
  console.log(`Expected! File does exist`);
} catch (err) {
  console.log(`Unexpected! Should not log`, err);
}
// Output: Expected! File does exist

fsPromises.writeFile example

By default, fsPromises.writeFile creates files that don't exist, which means it won't error if the file is missing. The r+ filesystem flag can change this behavior. Here's what the flag does: "Open file for reading and writing. An exception occurs if the file does not exist."

try {
  await fs.writeFile('missing.txt', 'data', { flag: 'r+' });
  console.log(`Unexpected! Should not log`);
} catch (err) {
  console.log(`Expected! File does not exist`, err);
}
// Output: Expected! File does not exist Error: ENOENT: no such file or directory, open ...

try {
  await fs.writeFile('exists.txt', 'data', { flag: 'r+' });
  console.log(`Expected! File does exist`);
} catch (err) {
  console.log(`Unexpected! Should not log`, err);
}
// Output: Expected! File does exist

Comments

-1

vannilla Nodejs callback

function fileExists(path, cb){
  return fs.access(path, fs.constants.F_OK,(er, result)=> cb(!err && result)) //F_OK checks if file is visible, is default does no need to be specified.
}

the docs say you should use access() as a replacement for deprecated exists()

Nodejs with build in promise (node 7+)

function fileExists(path, cb){
  return new Promise((accept,deny) => 
    fs.access(path, fs.constants.F_OK,(er, result)=> cb(!err && result))
  );
}

Popular javascript framework

fs-extra

var fs = require('fs-extra')
await fs.pathExists(filepath)

As you see much simpler. And the advantage over promisify is that you have complete typings with this package (complete intellisense/typescript)! Most of the cases you will have already included this library because (+-10.000) other libraries depend on it.

1 Comment

Native fs/promisses has landed in Node 10+
-6

Using Promise

import { existsSync } from 'fs'

const exists = (filepath) => new Promise((res) => {
  existsSync(filepath) ? res(true) : res(false)
})

// Usage #1 (async/await)
const doesItExist = await exists('foo.txt')
if (doesItExist == false) {
  // create the file
}

// Usage #2 (thenable)
exists('foo.txt').then(doesItExist => {
  if (!doesItExist) {
    // create file
  }
})

But honestly it's rare to have a case like that,
Usually you'll just go with

import { existsSync as exists } from 'fs'

if (exists('foo.txt')) {
  // do something
}

9 Comments

It's a much better solution to import { promisify } from 'util' instead of using the *sync methods for all file system operations. In this particular example, the promise doesn't do anything for you because the operation in the promise is synchronous.
const doesItExist = await exists('foo.txt') if (doesItExist == false) { could be simply if (!(await exists('foo.txt'))) {. "But honestly it's rare to have a case like that" -- is running an Express server a rare case? Seems like resorting to blocking Sync functions is the exceptional case, not the other way around.
@ggorlen--onLLMstrike My answer was so ahead of its time, nobody understood haha. The two solutions I am giving are not the same as you may think, one is synchronous (the 2nd snippet), and the first one is wrapped in a promise so you can use it both synchronously and asynchronously depending on your usecase:)
Wrapping synchronous code in a promise doesn't make the operation any less synchronous. It still blocks the thread, then forces the calling code async with absolutely no benefit. It's misleading and worse than just calling the sync version directly, which is already bad. The only truly async versions are the ones given to you by the Node API. Sorry, but the answer isn't ahead of its time, it's misguided and incorrect and I suggest deleting it.
@ggorlen--onLLMstrike it does, try running the code to see for yourself. You can do exists('foo.txt').then(...); ... (in other words executing code without waiting for exists function to give an answer. ¯_(ツ)_/¯
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.