335

How do I check for the existence of a file?

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
RomanGor
  • 3,835
  • 2
  • 19
  • 26
  • 7
    As of 2018, use `fs.access('file', err => err ? 'does not exist' : 'exists')`, see [fs.access](https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback) – mb21 Jan 12 '19 at 16:59
  • 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. – Mitya Feb 01 '23 at 13:46

22 Answers22

417

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')) { 
  // ...
}
João Pimentel Ferreira
  • 14,289
  • 10
  • 80
  • 109
dardar.moh
  • 5,987
  • 3
  • 24
  • 33
  • 1
    But, as it turned out, `fs.exists` works too. I have had problems with permissions to the file. – RomanGor Jul 17 '13 at 12:38
  • 18
    `path.exists` actually is deprecated in favor of `fs.exists` – Arnaud Rinquin May 26 '14 at 16:32
  • 60
    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. – Antrikshy Mar 29 '15 at 18:46
  • 10
    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... – newprog Apr 13 '15 at 10:40
  • 24
    @Antrikshy `fs.existsSync` is no longer depricated, though `fs.exists` still is. – RyanZim Oct 12 '17 at 20:50
  • Is this a promise or something? Doesn't seem to be executed asynchronously. – Philll_t Oct 02 '18 at 23:32
  • As @newprog said, the Nodejs documentation for fsPromises(fsp) indeed says that they are correct: Calling fsp.access() then calling fsp.open() can "introduce a race condition" in which "other processes may change the file's state between the two calls". "Instead, [...] open/read/write the file directly and handle the error [if] not accessible" [Last part of linked section in docs](https://nodejs.org/api/fs.html#fs_fspromises_access_path_mode) – vipatron Nov 27 '19 at 20:17
  • @Antrikshy the [`nodejs fs documentation`](https://nodejs.org/api/fs.html#fs_fs_existssync_path) only says `fs.exists` is deprecated, but that `fs.existsSync` is fine ??? – oldboy Jan 03 '20 at 02:18
  • 1
    Why not just try opening the file? Because that requires catching the error and distinguishing the error thrown as a result of file's nonexistence from any other possible error, while an `exists()` kind of API answers the question directly and can be used directly in a condition. – Szczepan Hołyszewski Jan 04 '21 at 09:32
  • 2
    pls remove the 1st part of the answer, which works only for node < 0.12 (way too old) – Marius Dec 29 '21 at 13:30
  • Answering the question "Why not just try opening the file?": I need to just check if an auto-generated file exists, to pre-check the state of the app, but I don't need to read the content yet. – kca Nov 02 '22 at 04:35
182

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;
}
SColvin
  • 11,584
  • 6
  • 57
  • 71
mido
  • 24,198
  • 15
  • 92
  • 117
  • 5
    Upvoted, this is definitely the most modern (2018) way to detect if a file exists in Node.js – AKMorris Feb 15 '18 at 22:00
  • 2
    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. https://nodejs.org/api/fs.html#fs_fs_stat_path_callback – Justin Apr 16 '18 at 13:05
  • 1
    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. – samson Apr 20 '18 at 02:56
  • 1
    Could try doing it with `fs.promises.access(path, fs.constants.F_OK);` to simply make it a Promise instead of creating a Promise. – Jeremy Trpka Jun 20 '20 at 13:50
  • I have been using an even shorter version of this: does not exist: `!(await fs.stat(path).catch(() => false))` exists: `!!(await fs.stat(path).catch(() => false))` – antitoxic Aug 26 '20 at 06:57
  • 5
    This code is so ugly compared to the simple `fs.exists` one...really wonder why they force us to use such alternatives :'-( – TOPKAT Jun 20 '21 at 10:15
  • `fs.constants.F_OK`, the flag indicating that the file is visible to the calling process, is **not needed.** It is the default. Just `try`–`catch` `await fs.access(path)`. – Константин Ван May 26 '22 at 18:47
93

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.

mkobit
  • 43,979
  • 12
  • 156
  • 150
Paul Ho
  • 1,119
  • 8
  • 8
  • 27
    @Imeurs but https://nodejs.org/api/fs.html#fs_fs_existssync_path say: Note that fs.exists() is deprecated, but fs.existsSync() is not. – HaveF Dec 09 '16 at 03:01
  • 13
    `fs.existsSync` was deprecated, but it no longer is. – RyanZim Oct 12 '17 at 20:51
  • 1
    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. – ggorlen Jul 22 '21 at 17:44
47

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

  • 9
    A couple characters shorter and maybe easier to read: `const fileExists = path => fs.promises.stat(path).then(() => true, () => false);` – ggorlen Jul 22 '21 at 17:51
20

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.");
}
lmeurs
  • 16,111
  • 4
  • 27
  • 30
  • 15
    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.)" – shreddish May 08 '17 at 15:45
  • the first (from the top) answer, which mentioned where the `fs` variable comes from – d.k Jun 21 '17 at 18:35
  • At the time this answer was written, the info was correct; however, `fs.existsSync()` is no longer deprecated. – RyanZim Oct 12 '17 at 20:52
  • I'm sorry, but what does say that "`existsSync`" is deprecated exactly? – Artfaith Sep 06 '21 at 04:00
18

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");
}
Manohar Reddy Poreddy
  • 25,399
  • 9
  • 157
  • 140
  • 1
    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." – Alexandre Andrade Feb 23 '22 at 00:17
15

A concise solution in async await style:

import { stat } from 'fs/promises';

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

Stepan Zabelin
  • 347
  • 1
  • 4
  • 10
14

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
    } 
});
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.

Styx
  • 9,863
  • 8
  • 43
  • 53
chrisw
  • 407
  • 4
  • 12
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)

mikermcneil
  • 11,141
  • 5
  • 43
  • 70
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

Val
  • 65
  • 2
  • 12
Koushik Das
  • 9,678
  • 3
  • 51
  • 50
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);
    }
  });
});
Alexander Zeitler
  • 11,919
  • 11
  • 81
  • 124
2
  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);
      }
    });
D.Belda
  • 21
  • 1
2

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.

f1lt3r
  • 2,176
  • 22
  • 26
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!

Mohamed Allal
  • 17,920
  • 5
  • 94
  • 97
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?

Will
  • 24,082
  • 14
  • 97
  • 108
nthapa
  • 1,266
  • 4
  • 13
  • 22
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.
Craig Hicks
  • 2,199
  • 20
  • 35
1

For those who ❤️ async-await

import fsp from 'fs/promises';

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

const path = './dir/file.pdf';
console.log(await isFileExist(path));
Mehmet Filiz
  • 608
  • 5
  • 18
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

0

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.

Community
  • 1
  • 1
Joel Harkes
  • 10,975
  • 3
  • 46
  • 65
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);
}());
BrunoLM
  • 97,872
  • 84
  • 296
  • 452
-5

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
}
vdegenne
  • 12,272
  • 14
  • 80
  • 106
  • 1
    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. – Max Feb 27 '23 at 16:13
  • `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 Mar 19 '23 at 22:16
  • @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:) – vdegenne Jun 16 '23 at 21:12
  • 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 Jun 16 '23 at 22:04
  • @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. ¯\_(ツ)_/¯ – vdegenne Jun 16 '23 at 22:07
  • I don't have to run this to see that it's wrong. You can't slap a promise on synchronous code and expect it to magically become nonblocking. Asynchrony is a characteristic of the API call, not something you can magically sprinkle on top of synchronous code. No amount of promises changes sync code to async. The `.then()` is just misleading the caller. You can slap a promise onto a function that runs a `for` loop that counts to a million and the code will still tie up the Node thread until it's done, just like `existsSync` will. – ggorlen Jun 16 '23 at 22:10
  • @ggorlen--onLLMstrike I usually don't care about performances (patience is a vertue), I prefer being practical. Of course I would always prefer using `fs/promises`, my answer is outdated anyway, but I wouldn't mind using this solution for something else if that helps hybrid code. – vdegenne Jun 16 '23 at 22:14
  • The benefit of the sync version is that you don't need to use promises, but here, you get all of the slowness of sync code, _plus_ all of the coding pain of promises. Basically it's the worst of both worlds, which is indefensible any way you cut it. Even if you're patient and like slow code, this is still unusable--you'd just use `existsSync` without the silly, misleading promise wrapper. Two good options: efficient promise-based code (best) or slow, synchronous code (acceptable in some cases). This proposal: slow and promise-based for no good reason (unacceptable in any situation). – ggorlen Jun 16 '23 at 22:19
  • @ggorlen--onLLMstrike I am not saying it's a good solution, do not misinterpret my words:) My answer received 5 negative votes for a reason. I was just trying to be creative :D – vdegenne Jun 16 '23 at 23:00