337

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)
3

15 Answers 15

431

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

Sign up to request clarification or add additional context in comments.

5 Comments

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.
This is the perfect answer for this exact question. Thank you, it helped me a lot! @RaviLuthra is 100% correct.
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. –
Obviously import.meta.url is undefined when cat script.js | node --input-type module
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.
243

__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.

6 Comments

Also you can't use some of the Global variables inside RequireJS modules. If you use RequireJS on the server side, see stackoverflow.com/questions/9027429/….
Yeah, that should really be added to the answer Eye, because that's what got me.
Not adding that in to the REPL's load script is obnoxious. I can't think of any reason it wouldn't be there...
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
upvoted! saved me 15 mins as I was wondering wtf is happening
|
190

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

3 Comments

if you use nesh you can define this as part of your load script; it's nifty
or __dirname = process.cwd() or __dirname=fs.realpathSync('.') or __dirname = process.env.PWD
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.
73

In ES6 use:

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

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

8 Comments

You don't need to import core modules in the REPL; it will load them on the fly for you.
This gives the current working directory, not the directory of the current .js file.
@Dirbaio, what would be the current .js file when you're in the REPL?
@c24w just checked, it seems to give the CWD
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.
|
26

-> 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'))

3 Comments

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 nodejs.org/docs/latest-v14.x/api/esm.html#esm_import_meta and stackoverflow.com/questions/46745014/…
This worked for me inside a docker. Thanks
does it works with browser?
13

Starting from Nodejs v20, there is a better way:

const __dirname = import.meta.dirname;

https://nodejs.org/api/esm.html#differences-between-es-modules-and-commonjs

Comments

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').

Comments

7

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.......

2 Comments

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 __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.
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.

Comments

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 Comment

You don't need to require core modules in the REPL; it will load them on the fly for you.
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();

3 Comments

If you're not running this through the REPL, you can use __dirname and __filename.
This is the only answer that at least tries to provide correct solution.
@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 :)
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

1 Comment

__dirname (with two underscores) does not work in the REPL
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)
}

Comments

0

All in one solution, for handling cases of js, mjs, cjs files existing inside a single project and errors from bundlers.

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

function getScriptFileAbsolutePath(importMeta) {
  try {
    return { __dirname, __filename };
  } catch (e) {
    if (!importMeta?.url) {
      throw new Error("bad importMeta");
    }
    let __filename = fileURLToPath(importMeta.url);
    let __dirname = dirname(__filename);
    return { __dirname, __filename };
  }
}

console.log(getScriptFileAbsolutePath(import.meta));

Comments

0

My issue was that there were no errors generated by either typescript or eslint about this in my ESM project. Adding the following to my eslint config fixed this:

{
  rules: {
    // Disallow commonjs globals
    "no-restricted-globals": [
      "error",
      { name: "__filename" },
      { name: "__dirname" },
      { name: "require" },
      { name: "module" },
      { name: "exports" },
    ],
  }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.