process.cwd()
Returns the absolute path of the directory the Node.js process is currently working in.
process.cwd()- Added in Node.js v0.1.8
Return value
stringThe absolute path of the process's current working directory.
Errors
Throws an ENOENT error if the current working directory has been deleted or is no longer accessible.
process.cwd() returns the directory the process is anchored to right now. Every relative path you hand to fs, path.resolve() or require() of a runtime-computed path is resolved against it, so it quietly decides what half your file operations actually touch.
When to reach for it
Use it for anything that should follow the user: a config file discovered in the project root, an output directory a CLI writes into, a glob the caller typed. Those should be relative to where the command was invoked.
What trips people up
The working directory is a property of the invocation, not of the file. Running node scripts/build.js from the project root gives a cwd of the project root, while cd scripts && node build.js gives scripts — and every relative fs.readFile() in that script now looks somewhere else. When you want a path relative to the source file, use __dirname (CommonJS) or import.meta.dirname (ESM) instead.
It is also mutable: any call to process.chdir(), including one buried in a dependency, changes the answer for the whole process. Call process.cwd() at the point of use rather than caching it, or capture it once at startup and resolve everything against that snapshot.
Example
When to use it
- Resolve a config file the user expects to be found in the directory they ran the command from.
- Write CLI output into the caller's folder rather than next to the installed script.
- Print the working directory in an error message so a failing relative path can be diagnosed.
- Build an absolute path with path.resolve() before passing it to a library that requires one.
Frequently asked questions
What is the difference between process.cwd() and __dirname?
process.cwd() is the directory the command was run from and can change during the process, while __dirname is the directory of the source file and is fixed. Use cwd for user-supplied paths and __dirname (or import.meta.dirname in ESM) for files shipped alongside your code.
Why does my relative fs.readFile() path work in one terminal but not another?
Relative paths resolve against process.cwd(), which depends on where the command was launched, not where the file lives. Print process.cwd() in the failing case, or build the path with path.resolve(__dirname, 'file.txt') if it should always be found next to the script.
Can process.cwd() throw?
Yes — if the directory the process is running in is deleted or unmounted, the call fails with ENOENT because the process still holds a handle to a directory that no longer has a path. Recreating the directory does not help; the process must chdir somewhere valid.
More examples
Working directory versus script directory
The output shows the two anchors diverging for one single run. `data.csv` resolves next to where the user stood, which is what you want for their input; `template.html` resolves next to the source file, which is what you want for an asset shipped with the code. Running the same script as `cd /srv/app/scripts && node report.js` moves the first path and leaves the second untouched. In ESM the equivalent of `__dirname` is `import.meta.dirname`.
const path = require('node:path');
// File on disk: /srv/app/scripts/report.js
console.log('cwd :', process.cwd());
console.log('__dirname:', __dirname);
console.log('user file:', path.resolve('data.csv'));
console.log('bundled :', path.join(__dirname, 'template.html'));
// $ cd /srv/app && node scripts/report.js
// cwd : /srv/app
// __dirname: /srv/app/scripts
// user file: /srv/app/data.csv
// bundled : /srv/app/scripts/template.htmlFinding the project root by walking up
The output shows the search succeeding from a nested directory: the loop starts at the working directory and climbs until it finds a `package.json`. The `parent === dir` check is the important part — at the filesystem root `path.dirname('/')` returns `'/'`, so without it the loop never ends when the file is genuinely absent.
const fs = require('node:fs');
const path = require('node:path');
function findProjectRoot(start = process.cwd()) {
let dir = path.resolve(start);
while (true) {
if (fs.existsSync(path.join(dir, 'package.json'))) return dir;
const parent = path.dirname(dir);
if (parent === dir) return null; // reached the filesystem root
dir = parent;
}
}
const root = findProjectRoot();
console.log('project root:', root);
console.log('config path :', root && path.join(root, 'config', 'app.json'));
// project root: /srv/app
// config path : /srv/app/config/app.json
Discussion