318

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

387

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

5
  • 43
    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. Commented Sep 4, 2020 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
    Commented Dec 29, 2020 at 8: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. – Commented Dec 30, 2020 at 18:45
  • 1
    Obviously import.meta.url is undefined when cat script.js | node --input-type module Commented May 21, 2022 at 15:42
  • 2
    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
    Commented Apr 27, 2023 at 12:56
239

__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
  • 10
    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/….
    – esengineer
    Commented Nov 5, 2012 at 8:25
  • 2
    Yeah, that should really be added to the answer Eye, because that's what got me. Commented Oct 12, 2015 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
    Commented Nov 18, 2015 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 Commented Aug 26, 2016 at 18:56
  • upvoted! saved me 15 mins as I was wondering wtf is happening
    – PirateApp
    Commented Nov 6, 2018 at 5:15
182

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
  • if you use nesh you can define this as part of your load script; it's nifty
    – jcollum
    Commented Nov 18, 2015 at 21:15
  • 2
    or __dirname = process.cwd() or __dirname=fs.realpathSync('.') or __dirname = process.env.PWD
    – Jthorpe
    Commented Apr 6, 2016 at 4: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
    Commented Jun 16, 2016 at 15:22
71

In ES6 use:

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

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

8
  • You don't need to import core modules in the REPL; it will load them on the fly for you.
    – c24w
    Commented Oct 31, 2019 at 12:15
  • 1
    This gives the current working directory, not the directory of the current .js file.
    – Dirbaio
    Commented Dec 10, 2019 at 16:39
  • @Dirbaio, what would be the current .js file when you're in the REPL?
    – c24w
    Commented Feb 3, 2020 at 10:27
  • @c24w just checked, it seems to give the CWD
    – Dirbaio
    Commented Feb 3, 2020 at 23:11
  • 34
    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. Commented Jun 10, 2020 at 11:20
23

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

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

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

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
  • 1
    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
    Commented Dec 2, 2020 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. Commented Nov 26, 2021 at 11:42
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.

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
  • 1
    You don't need to require core modules in the REPL; it will load them on the fly for you.
    – c24w
    Commented Oct 31, 2019 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();
3
  • If you're not running this through the REPL, you can use __dirname and __filename.
    – c24w
    Commented Nov 12, 2019 at 10:48
  • 1
    This is the only answer that at least tries to provide correct solution. Commented Jun 10, 2020 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
    Commented Jun 15, 2020 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

1
  • __dirname (with two underscores) does not work in the REPL Commented Feb 25, 2018 at 10:32
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)
}
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));
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" },
    ],
  }
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.