Introduction
Node.js resolves require() paths relative to the current module file, not the process working directory. When a script is run from a different directory, or when the project structure changes, relative paths may resolve to non-existent locations. This causes MODULE_NOT_FOUND / ENOENT errors that work in development but fail in production or when run from cron.
Symptoms
Error: Cannot find module './config/database'Error: ENOENT: no such file or directory, open './data/file.json'- Works when run from project root but fails from other directories
- Works in development but fails in production deployment
- Error after
cdto a different directory before running the script
``` $ node src/server.js Error: Cannot find module './config/database' Require stack: - /home/user/project/src/server.js at Module._resolveFilename (node:internal/modules/cjs/loader:1075:15) at Module._load (node:internal/modules/cjs/loader:920:27) at Module.require (node:internal/modules/cjs/loader:1141:19)
# The file exists at /home/user/project/config/database.js # But require resolves relative to src/, not project root ```
Common Causes
require('./config')resolves relative to the calling file, not cwd- Running scripts from different working directory (cron, systemd)
- Using
./paths for non-module files (fs.readFile) - Project restructuring changing relative paths
- ES modules with different resolution rules than CommonJS
Step-by-Step Fix
- 1.Use __dirname for file-relative paths:
- 2.```javascript
- 3.// WRONG - resolves relative to process.cwd(), not this file
- 4.const config = require('./config/database');
- 5.const data = fs.readFileSync('./data/file.json');
// CORRECT - resolves relative to this file's directory const path = require('path'); const config = require(path.join(__dirname, '../config/database')); const data = fs.readFileSync(path.join(__dirname, '../data/file.json')); ```
- 1.Use path.resolve for absolute paths:
- 2.```javascript
- 3.const path = require('path');
// Resolve from project root regardless of cwd const projectRoot = path.resolve(__dirname, '..'); const configPath = path.join(projectRoot, 'config', 'database.js'); const config = require(configPath);
// Or define a helper const root = path.resolve(__dirname, '..'); const resolveFromRoot = (...parts) => path.join(root, ...parts);
const config = require(resolveFromRoot('config', 'database')); const data = fs.readFileSync(resolveFromRoot('data', 'file.json'), 'utf-8'); ```
- 1.Set NODE_PATH for module resolution:
- 2.```bash
- 3.# Add project root to module search path
- 4.export NODE_PATH=/var/www/html
- 5.node src/server.js
# Now require resolves from project root // In src/server.js const config = require('config/database'); // Finds /var/www/html/config/database.js
// Or in package.json "scripts": { "start": "NODE_PATH=. node src/server.js" } ```
- 1.Handle ES modules with import.meta.url:
- 2.```javascript
- 3.// ESM does not have __dirname
- 4.import { fileURLToPath } from 'url';
- 5.import path from 'path';
const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename);
const configPath = path.join(__dirname, '../config/database.js'); const config = await import(configPath);
// Or use a helper import { resolve } from 'path'; const rootDir = resolve(__dirname, '..'); ```
- 1.Use module-alias for cleaner imports:
- 2.```bash
- 3.npm install module-alias
- 4.
` - 5.```javascript
- 6.// At the very top of your entry point
- 7.const moduleAlias = require('module-alias');
- 8.moduleAlias.addAlias('@config', __dirname + '/config');
- 9.moduleAlias.addAlias('@utils', __dirname + '/utils');
// Then anywhere in your code const config = require('@config/database'); const helper = require('@utils/format'); ```
Prevention
- Always use
__dirnameorpath.resolve()for file paths - Never use
./for paths that need to work from different working directories - Add integration tests that run scripts from different directories
- Use
module-aliasor similar for cleaner, absolute-style imports - In cron jobs, always
cdto project root before running scripts: - ```cron
- 0 2 * * * cd /var/www/html && node src/cron/cleanup.js
`- Use
process.cwd()explicitly when you need the working directory - Document the expected working directory in your project README