ReferenceError: exports is not defined is a module-format mismatch error at its core — code written for CommonJS (using exports.foo = ... or module.exports = ...) is being executed in a context that treats it as an ES module instead, where exports simply isn't a recognized global.
This error means JavaScript code containing CommonJS-style export syntax (exports.x = ...) is running in an ES module context — ES modules use export/import syntax and don't provide the exports or module objects CommonJs relies on, so any CommonJS-authored code executed as if it were an ES module hits this reference immediately.
Why This Error Happens
Node.js and browsers determine whether to treat a file as CommonJS or an ES module based on several signals — file extension (.cjs vs .mjs), the "type" field in the nearest package.json, or <script type="module"> in HTML. When these signals disagree with the actual syntax used in the file (a .js file written in CommonJS syntax, but package.json declares "type": "module", causing Node to treat all .js files as ESM), the mismatch produces this error.
Reproducing the Error
A package.json declaring ESM, but a file still written in CommonJS syntax:
// package.json
{ "type": "module" }
// utils.js — written in CommonJS syntax, but package.json says "type": "module"
exports.formatDate = function (date) {
return date.toISOString();
};
// ReferenceError: exports is not defined
// (Node treats this file as ESM because of package.json, but the syntax is CommonJS)
Core Concepts Behind This Error
package.json's "type" field determines the default module system for .js files in that package, overriding what the file's syntax might suggest — "type": "module" treats .js as ESM, "type": "commonjs" (or omitting the field, which defaults to commonjs) treats .js as CommonJS; a mismatch between this setting and a specific file's actual syntax is the most common cause.
File extensions .cjs and .mjs explicitly force a module system regardless of package.json's "type" field — this is the standard escape hatch for a package that's mostly one module type but needs a specific file to be the other, and is often the cleanest fix for a single misbehaving file in an otherwise-consistent codebase.
A build tool or bundler misconfiguration can also produce this error by outputting CommonJS syntax into a file or bundle that gets loaded as an ES module (or vice versa) — this happens when a bundler's output format setting doesn't match how the consuming environment will actually load the file.
Third-party CommonJS packages imported into an ESM project generally work fine via Node's CommonJS/ESM interop, since Node handles requiring CommonJS packages from ESM code automatically — this error is specifically about your own file's syntax mismatching its own execution context, not usually about a dependency's format.
Fixing "exports Is Not Defined"
Fix 1: Convert the file to ES module syntax to match the project's declared module type (generally the preferred fix for actively maintained ESM projects):
// utils.js — converted to ESM syntax
export function formatDate(date) {
return date.toISOString();
}
Fix 2: Rename the specific file to .cjs to force CommonJS treatment for just that file, when converting isn't immediately practical or the file is a build script/config that's more naturally CommonJS:
// utils.cjs — explicit CommonJS regardless of package.json's "type"
exports.formatDate = function (date) {
return date.toISOString();
};
Fix 3: For a build tool config file specifically expecting CommonJS in an ESM project, use the tool's CommonJS-specific extension or configuration option, since many build tools have this exact scenario as a documented case:
// webpack.config.cjs instead of webpack.config.js, in a "type": "module" project
module.exports = { /* ... */ };
Should You Convert Your Whole Project to ESM or Just Fix the One File?
For new projects or projects already mostly using ESM syntax, converting the remaining CommonJS files is generally the more consistent, forward-looking fix, since ESM is the standard JavaScript module system going forward. For a legacy codebase heavily invested in CommonJS, renaming the specific offending file to .cjs (or removing "type": "module" if it was added without full conversion) is the more pragmatic immediate fix — full migration can happen deliberately later rather than as a reactive patch.
Preventing This Error in Production
Keep module syntax consistent with your project's declared "type" in package.json, using explicit .cjs/.mjs extensions for any deliberate exceptions rather than letting syntax and configuration silently drift apart. When migrating a project from CommonJS to ESM (or vice versa), do it as a deliberate, complete pass rather than incrementally, since partial migrations are exactly what produces this class of error scattered unpredictably across a codebase.
If you hit this error, check your nearest package.json's "type" field first, then check whether the specific file's syntax matches what that setting expects — the fix is almost always aligning one or the other, not a deeper investigation.