Node.js "__dirname is not defined in ES module scope" in CI
By Kaveh Alemi·Latchkey
ESM does not define __dirname or __filename. Code that relied on those CommonJS globals throws a ReferenceError once the file runs as an ES module.
What this error means
After enabling "type": "module" (or running a built ESM bundle), any use of __dirname/__filename fails in CI with a ReferenceError.
node
ReferenceError: __dirname is not defined in ES module scope
at file:///work/repo/dist/config.js:4:21
Diagnose it: what is different about the runner?
A build that passes locally and fails on a runner differs in a small number of predictable ways. Check those before changing build configuration, because the build config is usually not the thing that changed.
ESM intentionally omits __dirname/__filename. Any code or dependency-adjacent helper that uses them breaks under ESM.
How to fix it
Derive the directory from import.meta.url
Reconstruct __dirname using fileURLToPath and path.dirname.
src/config.js
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
Use import.meta.dirname on newer Node
Recent Node versions expose import.meta.dirname and import.meta.filename directly.
src/config.js
const here = import.meta.dirname; // Node 20.11+ / 21.2+
The three that account for most of them
Case sensitivity. Linux runners are case sensitive, macOS is not. An import with the wrong case resolves locally and fails in CI.
Out of memory. Exit code 137 is a SIGKILL from the kernel, not a build error. Raise --max-old-space-size or use a larger runner.
devDependencies pruned.NODE_ENV=production makes npm ci skip devDependencies, so the build tool itself goes missing. Set it after install, not before.
How to prevent it
Add the fileURLToPath shim once in a shared module when migrating to ESM.
Pin a Node version in CI that matches the import.meta features you use.
Grep for __dirname/__filename before flipping a package to "type": "module".
Frequently asked questions
What causes Node.js "__dirname is not defined in ES module scope" in CI?
commonjs globals removed in esm. ESM intentionally omits __dirname/__filename.
How do I fix Node.js "__dirname is not defined in ES module scope" in CI?
There are 2 fixes depending on which cause you have: derive the directory from import.meta.url and use import.meta.dirname on newer node. Work through them in order, since the first is the most common.
What does Node.js "__dirname is not defined in ES module scope" in CI actually mean?
After enabling "type": "module" (or running a built ESM bundle), any use of __dirname/__filename fails in CI with a ReferenceError.
How do I stop Node.js "__dirname is not defined in ES module scope" in CI happening again?
Add the fileURLToPath shim once in a shared module when migrating to ESM. The prevention section lists 3 changes that keep it from recurring.