[node.js] Determine project root from a running node.js application

Is there a better way than process.cwd() to determine the root directory of a running node.js process? Something like the equivalent of Rails.root, but for Node.js. I'm looking for something that is as predictable and reliable as possible.

This question is related to node.js

The answer is


the easiest way to get the global root (assuming you use NPM to run your node.js app 'npm start', etc)

var appRoot = process.env.PWD;

If you want to cross-verify the above

Say you want to cross-check process.env.PWD with the settings of you node.js application. if you want some runtime tests to check the validity of process.env.PWD, you can cross-check it with this code (that I wrote which seems to work well). You can cross-check the name of the last folder in appRoot with the npm_package_name in your package.json file, for example:

    var path = require('path');

    var globalRoot = __dirname; //(you may have to do some substring processing if the first script you run is not in the project root, since __dirname refers to the directory that the file is in for which __dirname is called in.)

    //compare the last directory in the globalRoot path to the name of the project in your package.json file
    var folders = globalRoot.split(path.sep);
    var packageName = folders[folders.length-1];
    var pwd = process.env.PWD;
    var npmPackageName = process.env.npm_package_name;
    if(packageName !== npmPackageName){
        throw new Error('Failed check for runtime string equality between globalRoot-bottommost directory and npm_package_name.');
    }
    if(globalRoot !== pwd){
        throw new Error('Failed check for runtime string equality between globalRoot and process.env.PWD.');
    }

you can also use this NPM module: require('app-root-path') which works very well for this purpose


1- create a file in the project root call it settings.js

2- inside this file add this code

module.exports = {
    POST_MAX_SIZE : 40 , //MB
    UPLOAD_MAX_FILE_SIZE: 40, //MB
    PROJECT_DIR : __dirname
};

3- inside node_modules create a new module name it "settings" and inside the module index.js write this code:

module.exports = require("../../settings");

4- and any time you want your project directory just use

var settings = require("settings");
settings.PROJECT_DIR; 

in this way you will have all project directories relative to this file ;)


if you want to determine project root from a running node.js application you can simply just too.

process.mainModule.path

__dirname isn't a global; it's local to the current module so each file has its own local, different value.

If you want the root directory of the running process, you probably do want to use process.cwd().

If you want predictability and reliability, then you probably need to make it a requirement of your application that a certain environment variable is set. Your app looks for MY_APP_HOME (Or whatever) and if it's there, and the application exists in that directory then all is well. If it is undefined or the directory doesn't contain your application then it should exit with an error prompting the user to create the variable. It could be set as a part of an install process.

You can read environment variables in node with something like process.env.MY_ENV_VARIABLE.


Preamble

This is a very old question but it seems to still hit the nerve in 2020 as in 2012. I've checked all of the other answers and could not find a technique (note that this has its limitations, but all of the others are not applicable in every situation as well).

GIT + child process

If you are using GIT as your version control system, the problem of determining the project root can be reduced to (which I would consider the proper root of the project - after all, you would want your VCS to have the fullest visibility scope possible):

retrieve repository root path

Since you have to run a CLI command to do that, we will need to spawn a child process. Additionally, as project root is highly unlikely to change mid-runtime, we can use the synchronous version of the child_process module APIs at startup.

I found spawnSync() to be the most suitable for the job. As for the actual command to run, git worktree (with a --porcelain option for ease of parsing) is all we need to retrieve the absolute root path.

In the sample, I opted to return an array of paths because there might be more than one worktree (although they are likely to have common paths) just to be sure. Note that as we utilize a CLI command, shell option should be set to true (security shouldn't be an issue as there is no untrusted input).

Approach comparison and fallbacks

Understanding that a situation where VCS can be inaccessible is possible, I've included a couple of fallbacks after analyzing docs and other answers. To sum up, the solutions proposed boil down to (excluding third-party modules & package-specific):


| Solution                 | Advantage               | Main Problem                     |
| ------------------------ | ----------------------- | -------------------------------- |
| `__filename`             | points to module file   | relative to module               |
| `__dirname`              | points to module dir    | same as `__filename`             |
| `node_modules` tree walk | nearly guaranteed root  | complex tree walking if nested   |
| `path.resolve(".")`      | root if CWD is root     | same as `process.cwd()`          |
| `process.argv[1]`        | same as `__filename`    | same as `__filename`             |
| `process.env.INIT_CWD`   | points to `npm run` dir | requires `npm` && CLI launch     |
| `process.env.PWD`        | points to current dir   | relative to (is the) launch dir  |
| `process.cwd()`          | same as `env.PWD`       | `process.chdir(path)` at runtime |
| `require.main.filename`  | root if `=== module`    | fails on `require`d modules      |

From the comparison table above, the most universal are two approaches:

  • require.main.filename as an easy way to get root if require.main === module is met
  • node_modules tree walk proposed recently uses another assumption:

if the directory of the module has node_modules dir inside, it is likely to be the root

For the main app, it will get the app root and for the module - its project root.

Fallback 1. Tree walk

My implementation uses a more lax approach by stopping once a target directory is found as for a given module its root is its project root. One can chain the calls or extend it to make search depth configurable:

/**
 * @summary gets root by walking up node_modules
 * @param {import("fs")} fs
 * @param {import("path")} pt
 */
const getRootFromNodeModules = (fs, pt) =>

    /**
     * @param {string} [startPath]
     * @returns {string[]}
     */
    (startPath = __dirname) => {

        //avoid loop if reached root path
        if (startPath === pt.parse(startPath).root) {
            return [startPath];
        }

        const isRoot = fs.existsSync(pt.join(startPath, "node_modules"));

        if (isRoot) {
            return [startPath];
        }

        return getRootFromNodeModules(fs, pt)(pt.dirname(startPath));
    };

Fallback 2. Main module

The second implementation is trivial

/**
 * @summary gets app entry point if run directly
 * @param {import("path")} pt
 */
const getAppEntryPoint = (pt) =>

    /**
     * @returns {string[]}
     */
    () => {

        const { main } = require;

        const { filename } = main;

        return main === module ?
            [pt.parse(filename).dir] :
            [];
    };

Implementation

I would suggest use the tree walker as fallback because it is more versatile:

const { spawnSync } = require("child_process");
const pt = require('path');
const fs = require("fs");

/**
 * @summary returns worktree root path(s)
 * @param {function : string[] } [fallback]
 * @returns {string[]}
 */
const getProjectRoot = (fallback) => {

    const { error, stdout } = spawnSync(
        `git worktree list --porcelain`,
        {
            encoding: "utf8",
            shell: true
        }
    );

    if (!stdout) {
        console.warn(`Could not use GIT to find root:\n\n${error}`);
        return fallback ? fallback() : [];
    }

    return stdout
        .split("\n")
        .map(line => {
            const [key, value] = line.split(/\s+/) || [];
            return key === "worktree" ? value : "";
        })
        .filter(Boolean);
};

Disadvantages

The most obvious is having GIT installed and initialized which might be undesirable / implausible (side note: having GIT installed on production servers is not uncommon, nor is it unsafe, though). Can be mediated by fallbacks as described above.

Notes

  1. A couple of ideas for further extension of approach 1:
  • introduce config as a function parameter
  • export the function to make it a module
  • check if GIT is installed and / or initialized

References

  1. git worktree reference
  2. spawnSync reference
  3. require.main reference
  4. path.dirname() reference

Simple:

require('path').resolve('./')

Just use:

 path.resolve("./") ... output is your project root directory

Add this somewhere towards the start of your main app file (e.g. app.js):

global.__basedir = __dirname;

This sets a global variable that will always be equivalent to your app's base dir. Use it just like any other variable:

const yourModule = require(__basedir + '/path/to/module.js');

Simple...


Actually, i find the perhaps trivial solution also to most robust: you simply place the following file at the root directory of your project: root-path.js which has the following code:

import * as path from 'path'
const projectRootPath = path.resolve(__dirname)
export const rootPath = projectRootPath

A technique that I've found useful when using express is to add the following to app.js before any of your other routes are set

// set rootPath
app.use(function(req, res, next) {
  req.rootPath = __dirname;
  next();
});

app.use('/myroute', myRoute);

No need to use globals and you have the path of the root directory as a property of the request object.

This works if your app.js is in the root of your project which, by default, it is.


Finding the root path of an electron app could get tricky. Because the root path is different for the main process and renderer under different conditions such as production, development and packaged conditions.

I have written a npm package electron-root-path to capture the root path of an electron app.

$ npm install electron-root-path

or 

$ yarn add electron-root-path


// Import ES6 way
import { rootPath } from 'electron-root-path';

// Import ES2015 way
const rootPath = require('electron-root-path').rootPath;

// e.g:
// read a file in the root
const location = path.join(rootPath, 'package.json');
const pkgInfo = fs.readFileSync(location, { encoding: 'utf8' });

__dirname will give you the root directory, as long as you're in a file that's in the root directory.

// ProjectDirectory.js (this file is in the project's root directory because you are putting it there).
module.exports = {

    root() {
        return __dirname;
    }
}

In some other file:

const ProjectDirectory = require('path/to/ProjectDirectory');
console.log(`Project root directory is ${ProjectDirectory.root}`);

Make it sexy .

const users = require('../../../database/users'); //  what you have
// OR
const users = require('$db/users'); //  no matter how deep you are
const products = require('/database/products'); //  alias or pathing from root directory


Three simple steps to solve the issue of ugly path.

  1. Install the package: npm install sexy-require --save
  2. Include require('sexy-require') once on the top of your main application file.

    require('sexy-require');
    const routers = require('/routers');
    const api = require('$api');
    ...
    
  3. Optional step. Path configuration can be defined in .paths file on root directory of your project.

    $db = /server/database
    $api-v1 = /server/api/legacy
    $api-v2 = /server/api/v2
    

path.dirname(process.mainModule.filename);

Old question, I know, however no question mention to use progress.argv. The argv array includes a full pathname and filename (with or without .js extension) that was used as parameter to be executed by node. Because this also can contain flags, you must filter this.

This is not an example you can directly use (because of using my own framework) but I think it gives you some idea how to do it. I also use a cache method to avoid that calling this function stress the system too much, especially when no extension is specified (and a file exist check is required), for example:

node myfile

or

node myfile.js

That's the reason I cache it, see also code below.


function getRootFilePath()
{
        if( !isDefined( oData.SU_ROOT_FILE_PATH ) )
        {
            var sExt = false;

            each( process.argv, function( i, v )
            {
                 // Skip invalid and provided command line options
                if( !!v && isValidString( v ) && v[0] !== '-' )
                {
                    sExt = getFileExt( v );

                    if( ( sExt === 'js' ) || ( sExt === '' && fileExists( v+'.js' )) )
                    {

                        var a = uniformPath( v ).split("/"); 

                         // Chop off last string, filename
                        a[a.length-1]='';

                         // Cache it so we don't have to do it again.
                        oData.SU_ROOT_FILE_PATH=a.join("/"); 

                         // Found, skip loop
                        return true;
                    }
                }
            }, true ); // <-- true is: each in reverse order
        }

        return oData.SU_ROOT_FILE_PATH || '';
    }
}; 

Maybe you can try traversing upwards from __filename until you find a package.json, and decide that's the main directory your current file belongs to.


At top of main file add:

mainDir = __dirname;

Then use it in any file you need:

console.log('mainDir ' + mainDir);
  • mainDir is defined globally, if you need it only in current file - use __dirname instead.
  • main file is usually in root folder of the project and is named like main.js, index.js, gulpfile.js.

As simple as add this line to your module in root, usually it is app.js

global.__basedir = __dirname;

Then _basedir will be accessiable to all your modules.


process.mainModule is deprecated since v 14.0.0. When referring to the answer, please use require.main, the rest still holds.

process.mainModule.paths
  .filter(p => !p.includes('node_modules'))
  .shift()

Get all paths in main modules and filter out those with "node_modules", then get the first of remaining path list. Unexpected behavior will not throw error, just an undefined.

Works well for me, even when calling ie $ mocha.


Try path._makeLong('some_filename_on_root.js');

example:

cons path = require('path');
console.log(path._makeLong('some_filename_on_root.js');

That will return full path from root of your node application (same position of package.json)


There is an INIT_CWD property on process.env. This is what I'm currently working with in my project.

const {INIT_CWD} = process.env; // process.env.INIT_CWD 
const paths = require(`${INIT_CWD}/config/paths`);

Good Luck...


All these "root dirs" mostly need to resolve some virtual path to a real pile path, so may be you should look at path.resolve?

var path= require('path');
var filePath = path.resolve('our/virtual/path.ext');

I use this.

For my module named mymodule

var BASE_DIR = __dirname.replace(/^(.*\/mymodule)(.*)$/, '$1')


You can simply add the root directory path in the express app variable and get this path from the app. For this add app.set('rootDirectory', __dirname); in your index.js or app.js file. And use req.app.get('rootDirectory') for getting the root directory path in your code.


I know this one is already too late. But we can fetch root URL by two methods

1st method

var path = require('path');
path.dirname(require.main.filename);

2nd method

var path = require('path');
path.dirname(process.mainModule.filename);

Reference Link:- https://gist.github.com/geekiam/e2e3e0325abd9023d3a3


This will step down the directory tree until it contains a node_modules directory, which usually indicates your project root:

const fs = require('fs')
const path = require('path')

function getProjectRoot(currentDir = __dirname.split(path.sep)) {
  if (!currentDir.length) {
    throw Error('Could not find project root.')
  }
  const nodeModulesPath = currentDir.concat(['node_modules']).join(path.sep)
  if (fs.existsSync(nodeModulesPath) && !currentDir.includes('node_modules')) {
    return currentDir.join(path.sep)
  }
  return this.getProjectRoot(currentDir.slice(0, -1))
}

It also makes sure that there is no node_modules in the returned path, as that means that it is contained in a nested package install.


This will do:

path.join(...process.argv[1].split(/\/|\\/).slice(0, -1))

It work for me

process.env.PWD

I've found this works consistently for me, even when the application is invoked from a sub-folder, as it can be with some test frameworks, like Mocha:

process.mainModule.paths[0].split('node_modules')[0].slice(0, -1);

Why it works:

At runtime node creates a registry of the full paths of all loaded files. The modules are loaded first, and thus at the top of this registry. By selecting the first element of the registry and returning the path before the 'node_modules' directory we are able to determine the root of the application.

It's just one line of code, but for simplicity's sake (my sake), I black boxed it into an NPM module:

https://www.npmjs.com/package/node-root.pddivine

Enjoy!


Create a function in app.js

/*Function to get the app root folder*/

var appRootFolder = function(dir,level){
    var arr = dir.split('\\');
    arr.splice(arr.length - level,level);
    var rootFolder = arr.join('\\');
    return rootFolder;
}

// view engine setup
app.set('views', path.join(appRootFolder(__dirname,1),'views'));