269

From the node manual I see that I can get the directory of a file with __dirname, but from the REPL this seems to be undefined. Is this a misunderstanding on my side or where is the error?

$ node
> console.log(__dirname)
ReferenceError: __dirname is not defined
    at repl:1:14
    at REPLServer.eval (repl.js:80:21)
    at Interface.<anonymous> (repl.js:182:12)
    at Interface.emit (events.js:67:17)
    at Interface._onLine (readline.js:162:10)
    at Interface._line (readline.js:426:8)
    at Interface._ttyWrite (readline.js:603:14)
    at ReadStream.<anonymous> (readline.js:82:12)
    at ReadStream.emit (events.js:88:20)
    at ReadStream._emitKey (tty.js:320:10)
Flip
  • 6,233
  • 7
  • 46
  • 75
topskip
  • 16,207
  • 15
  • 67
  • 99
  • 32
    `__dirname` and `__filename` are also [not available when `node` is called with the `--experimental-modules` flag](https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-when-using-the-experimental-modules-flag). – Dan Dascalescu Dec 18 '18 at 05:17
  • 3
    I got this issue when using eslint, I had mistakenly set `"browser": true` instead of `"node": true` in my .eslintrc.json file. – Toivo Säwén Mar 25 '20 at 16:37
  • If nothing works here's a hack https://stackoverflow.com/a/49879107/696535 – Pawel Jul 17 '21 at 10:25

12 Answers12

285

If you are using Node.js modules, __dirname and __filename don't exist.

From the Node.js documentation:

No require, exports, module.exports, __filename, __dirname

These CommonJS variables are not available in ES modules.

require can be imported into an ES module using module.createRequire().

Equivalents of __filename and __dirname can be created inside of each file via import.meta.url:

import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

https://nodejs.org/docs/latest-v15.x/api/esm.html#esm_no_filename_or_dirname

advaiyalad
  • 144
  • 1
  • 11
AMS777
  • 4,609
  • 1
  • 18
  • 21
  • 38
    Technically this is the only correct answer here. All of the other solutions use the current working directory. Which is different from the __dirname feature that is really the folder holding the currently running script. – Ravi Luthra Sep 04 '20 at 20:19
  • 5
    This is the perfect answer for this exact question. Thank you, it helped me a lot! @RaviLuthra is 100% correct. – Karlsson Dec 29 '20 at 08:53
  • 3
    Concurr this is the only correct answer here "if" problem is relating to ES6 modules type of architecture. Import statement needs to reference path that evetnually gets passed downt to __dirname which is the feature that is really the folder holding the currently running script. – – Bruno Miyamotto Luque Dec 30 '20 at 18:45
  • 1
    Obviously `import.meta.url` is `undefined` when `cat script.js | node --input-type module` – Saber Hayati May 21 '22 at 15:42
  • REPL context is *not* ES module. This answer is completely missing the point of the original question. import.meta is inaccessible from a REPL context as @SaberHayati mentioned, and this answer does not work at all. I don't know why it's getting so many upvotes. – martian17 Apr 27 '23 at 12:56
232

__dirname is only defined in scripts. It's not available in REPL.

try make a script a.js

console.log(__dirname);

and run it:

node a.js

you will see __dirname printed.

Added background explanation: __dirname means 'The directory of this script'. In REPL, you don't have a script. Hence, __dirname would not have any real meaning.

Yaakov Belch
  • 4,692
  • 33
  • 39
qiao
  • 17,941
  • 6
  • 57
  • 46
  • 10
    Also you can't use some of the Global variables inside RequireJS modules. If you use RequireJS on the server side, see http://stackoverflow.com/questions/9027429/how-to-use-nodejs-global-module-objects-in-requirejs-modules. – esengineer Nov 05 '12 at 08:25
  • 2
    Yeah, that should really be added to the answer Eye, because that's what got me. – Tomáš Zato Oct 12 '15 at 17:14
  • 4
    Not adding that in to the REPL's load script is obnoxious. I can't think of any reason it wouldn't be there... – jcollum Nov 18 '15 at 21:16
  • 1
    I loaded a script file while inside the REPL using `.load script.js`. It's too bad __dirname still isn't available from within script.js – Kevin Wheeler Aug 26 '16 at 18:56
  • upvoted! saved me 15 mins as I was wondering wtf is happening – PirateApp Nov 06 '18 at 05:15
  • this just restated the question without answering it – Post Self May 13 '22 at 13:15
164

Building on the existing answers here, you could define this in your REPL:

__dirname = path.resolve(path.dirname(''));

Or:

__dirname = path.resolve();

If no path segments are passed, path.resolve() will return the absolute path of the current working directory.


Or @Jthorpe's alternatives:

__dirname = process.cwd();
__dirname = fs.realpathSync('.');
__dirname = process.env.PWD
c24w
  • 7,421
  • 7
  • 39
  • 47
  • if you use `nesh` you can define this as part of your load script; it's nifty – jcollum Nov 18 '15 at 21:15
  • 2
    or `__dirname = process.cwd()` or `__dirname=fs.realpathSync('.')` or `__dirname = process.env.PWD` – Jthorpe Apr 06 '16 at 04:31
  • 1
    `path.dirname` seems to not accept non-string values anymore in the newest major version, `6.0.0`, so the first suggestion in this answer will not work. – trysis Jun 16 '16 at 15:22
67

In ES6 use:

import path from 'path';
const __dirname = path.resolve();

also available when node is called with --experimental-modules

t-reksio
  • 3,251
  • 18
  • 12
  • You don't need to import core modules in the REPL; it will load them on the fly for you. – c24w Oct 31 '19 at 12:15
  • This gives the current working directory, not the directory of the current `.js` file. – Dirbaio Dec 10 '19 at 16:39
  • @Dirbaio, what would be the _current `.js` file_ when you're in the REPL? – c24w Feb 03 '20 at 10:27
  • @c24w just checked, it seems to give the CWD – Dirbaio Feb 03 '20 at 23:11
  • @Dirbaio I think that was my point. When you enter the REPL, there is no current JS file. What would you want `__dirname` to be, if not the CWD? – c24w Feb 05 '20 at 09:59
  • 25
    This is wrong. `__dirname` is meant to be current modules directory, but your solution makes it current working directory. How did this nonsen get so many upvotes is beyond my understanding. – Tomáš Zato Jun 10 '20 at 11:20
  • path.resolve() is the root dir of the project or CWD, it is not __dirname – Nikolay Makhonin Mar 08 '23 at 07:11
21

-> At ES6 version use :

import path from "path"
const __dirname = path.resolve();

-> And use it like this for example:

res.sendFile(path.join(__dirname ,'views','shop.html'))
myeongkil kim
  • 2,465
  • 4
  • 16
  • 22
AlexD
  • 301
  • 2
  • 4
  • 9
    This is **NOT** equivalent to `__dirname` but rather `process.cwd()`. For example, you will get different results when running the script from different directories. When using ESM a better approach is to use `import.meta.url`. See https://nodejs.org/docs/latest-v14.x/api/esm.html#esm_import_meta and https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-when-using-the-experimental-modules-flag – jacobq May 21 '21 at 17:12
  • This worked for me inside a docker. Thanks – Hayyaun Sep 03 '22 at 00:56
8

I was also trying to join my path using path.join(__dirname, 'access.log') but it was throwing the same error.

Here is how I fixed it:

I first imported the path package and declared a variable named __dirname, then called the resolve path method.

In CommonJS

var path = require("path");

var __dirname = path.resolve();

In ES6+

import path  from 'path';

const __dirname = path.resolve();

Happy coding.......

abdul-wahab
  • 2,182
  • 3
  • 21
  • 35
Desire Kaleba
  • 1,264
  • 11
  • 11
  • I am on node v15.3.0 and I do not need to use `path.resolve()`. `__dirname` just works out of the box. Is your answer still relevant to ES6+? – Zac Dec 02 '20 at 22:00
  • @Zac __dirname is only available on Node 14 or higher if you are using CommonJS. But ECMA is pushing towards ES modules being the standard instead of CommonJS. – Juha Untinen Nov 26 '21 at 11:42
7

As @qiao said, you can't use __dirname in the node repl. However, if you need need this value in the console, you can use path.resolve() or path.dirname(). Although, path.dirname() will just give you a "." so, probably not that helpful. Be sure to require('path').

jeremywoertink
  • 2,281
  • 1
  • 23
  • 29
4

If you got node __dirname not defined with node --experimental-modules, you can do :

const __dirname = path.dirname(import.meta.url)
                      .replace(/^file:\/\/\//, '') // can be usefull

Because othe example, work only with current/pwd directory not other directory.

user2226755
  • 12,494
  • 5
  • 50
  • 73
3

Seems like you could also do this:

__dirname=fs.realpathSync('.');

of course, dont forget fs=require('fs')

(it's not really global in node scripts exactly, its just defined on the module level)

  • 1
    You don't need to require core modules in the REPL; it will load them on the fly for you. – c24w Oct 31 '19 at 12:14
3

I was running a script from batch file as SYSTEM user and all variables like process.cwd() , path.resolve() and all other methods would give me path to C:\Windows\System32 folder instead of actual path. During experiments I noticed that when an error is thrown the stack contains a true path to the node file.

Here's a very hacky way to get true path by triggering an error and extracting path from e.stack. Do not use.

// this should be the name of currently executed file
const currentFilename = 'index.js';

function veryHackyGetFolder() {
  try {
    throw new Error();
  } catch(e) {
    const fullMsg = e.stack.toString();
    const beginning = fullMsg.indexOf('file:///') + 8;
    const end = fullMsg.indexOf('\/' + currentFilename);
    const dir = fullMsg.substr(beginning, end - beginning).replace(/\//g, '\\');
    return dir;
  }
}

Usage

const dir = veryHackyGetFolder();
Pawel
  • 16,093
  • 5
  • 70
  • 73
  • If you're not running this through the REPL, you _can_ use `__dirname` and `__filename`. – c24w Nov 12 '19 at 10:48
  • 1
    This is the only answer that at least tries to provide correct solution. – Tomáš Zato Jun 10 '20 at 11:21
  • @c24w I tried __dirname, __filename and everything else. No standard solution worked in my case. Here's my project which runs a process as SYSTEM from task scheduler if you're bored github.com/DVLP/Unscheduler. Any standard solution that otherwise works is obviously better than my hack above :) – Pawel Jun 15 '20 at 13:10
2

Though its not the solution to this problem I would like to add it as it may help others.

You should have two underscores before dirname, not one underscore (__dirname not _dirname).

NodeJS Docs

surj
  • 4,706
  • 2
  • 25
  • 34
Siva Prakash
  • 4,626
  • 34
  • 26
0

This is a workaround, but it works both in CommonJS and in ESModules. This can be used so far NodeJS is in a crisis due to the transition from CommonJS to ESModules. I have not found other ways. import.meta.url cannot be used, because TypeScript files will cease to be compiled in CommonJS.

__filename.ts

import { fileURLToPath } from 'url'

export function get__filename() {
  const error = new Error()
  const stack = error.stack
  const match = stack.match(/^Error\s+at[^\r\n]+\s+at *(?:[^\r\n(]+\((.+?)(?::\d+:\d+)?\)|(.+?)(?::\d+:\d+)?) *([\r\n]|$)/)
  const filename = match[1] || match[2]
  if (filename.startsWith('file://')) {
    return fileURLToPath(filename)
  }
  return filename
}

code.ts

if (typeof __filename === 'undefined') {
  global.__filename = get__filename()
  global.__dirname = path.dirname(__filename)
}
Nikolay Makhonin
  • 1,087
  • 12
  • 18