nextjs - ✅(Solved) Fix @next/eslint-plugin-next incorrect named exports [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#86504Fetched 2026-04-08 02:10:36
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1issue_type_added ×1labeled ×1subscribed ×1

Error Message

node -e "import {configs} from '@next/eslint-plugin-next';" file:///home/tobias/code/repro-eslint-mcp-jiti/[eval1]:1 import {configs} from '@next/eslint-plugin-next'; ^^^^^^^ SyntaxError: Named export 'configs' not found. The requested module '@next/eslint-plugin-next' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export, for example using:

import pkg from '@next/eslint-plugin-next'; const {configs} = pkg;

at #_instantiate (node:internal/modules/esm/module_job:254:21)
at async ModuleJob.run (node:internal/modules/esm/module_job:369:5)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:278:26)
at async ModuleLoader.executeModuleJob (node:internal/modules/esm/loader:275:20)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)

Node.js v24.11.0

Root Cause

@next/eslint-plugin-next defines top-level getters on exports Object.defineProperty(exports, "configs", { enumerable: true, get: () => configs }); Node ignores top-level getters for synthetic named exports when importing CJS as ESM.

typescript-eslint works because it assigns a data property at the top level: exports.configs = createConfigsGetters({ ... }); // data property Node sees a top-level data property → creates a synthetic named export → import { configs } works.

To fix @next/eslint-plugin-next do this:

// Instead of top-level getter:
Object.defineProperty(exports, "configs", {
 enumerable: true,
 value: configs  // <- data property, not a getter
});

Fix Action

Fixed

PR fix notes

PR #86620: fix(eslint-plugin-next): ensure named exports for ESM compatibility

Description (problem / solution / changelog)

What?

Refactored the exports in packages/eslint-plugin-next/src/index.ts to explicitly assign named exports (configs, rules, meta) to module.exports in a way that is statically analyzable by Node.js's CJS-ESM interop (specifically cjs-module-lexer).

Why?

Fixes #86504

When importing @next/eslint-plugin-next in an ESM environment (like eslint.config.js or using node -e "import ..."), named imports such as import { configs } from '@next/eslint-plugin-next' were failing.

This happened because swc compiles the previous export const syntax into Object.defineProperty getters. While valid CommonJS, Node.js's cjs-module-lexer cannot detect these dynamic getters as named exports, leading to a runtime error: SyntaxError: Named export 'configs' not found.

How?

I updated the entry point (src/index.ts) to:

  1. Directly assign module.exports = plugin for the default export.
  2. Explicitly assign exports.configs, exports.rules, and exports.meta as properties.

This pattern ensures that:

  • CommonJS consumers (using require) receive the expected plugin object with properties.
  • ESM consumers (using import) can successfully import named exports because cjs-module-lexer can now detect the exports.prop = ... pattern.

Verified the fix using the reproduction script from the issue: node -e "import {configs} from '@next/eslint-plugin-next'; console.log(Object.keys(configs))"

Output: [ 'recommended-legacy', 'core-web-vitals-legacy', 'recommended', 'core-web-vitals' ]Fixes #86504

Changed files

  • packages/eslint-plugin-next/src/index.ts (modified, +51/-34)

Code Example

> node -e "import {configs} from '@next/eslint-plugin-next';"
file:///home/tobias/code/repro-eslint-mcp-jiti/[eval1]:1
import {configs} from '@next/eslint-plugin-next';
        ^^^^^^^
SyntaxError: Named export 'configs' not found. The requested module '@next/eslint-plugin-next' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@next/eslint-plugin-next';
const {configs} = pkg;

    at #_instantiate (node:internal/modules/esm/module_job:254:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:369:5)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:278:26)
    at async ModuleLoader.executeModuleJob (node:internal/modules/esm/loader:275:20)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)

Node.js v24.11.0

---

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP Tue Nov 5 00:21:55 UTC 2024
  Available memory (MB): 31662
  Available CPU cores: 32
Binaries:
  Node: 24.11.0
  npm: 11.6.1
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 16.0.4 // Latest available version is detected (16.0.4).
  eslint-config-next: N/A
  react: 19.2.0
  react-dom: 19.2.0
  typescript: N/A
Next.js Config:
  output: N/A

---

> // Instead of top-level getter:
> Object.defineProperty(exports, "configs", {
>  enumerable: true,
>  value: configs  // <- data property, not a getter
> });
>
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/thernstig/eslint-mcp-jiti

To Reproduce

  1. Install the packages
  2. Execute this in a terminal: node -e "import {configs} from '@next/eslint-plugin-next';"

Current vs. Expected behavior

Expected

It should return with no errors.

Actual

> node -e "import {configs} from '@next/eslint-plugin-next';"
file:///home/tobias/code/repro-eslint-mcp-jiti/[eval1]:1
import {configs} from '@next/eslint-plugin-next';
        ^^^^^^^
SyntaxError: Named export 'configs' not found. The requested module '@next/eslint-plugin-next' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@next/eslint-plugin-next';
const {configs} = pkg;

    at #_instantiate (node:internal/modules/esm/module_job:254:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:369:5)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:278:26)
    at async ModuleLoader.executeModuleJob (node:internal/modules/esm/loader:275:20)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)

Node.js v24.11.0

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP Tue Nov 5 00:21:55 UTC 2024
  Available memory (MB): 31662
  Available CPU cores: 32
Binaries:
  Node: 24.11.0
  npm: 11.6.1
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 16.0.4 // Latest available version is detected (16.0.4).
  eslint-config-next: N/A
  react: 19.2.0
  react-dom: 19.2.0
  typescript: N/A
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Linting

Which stage(s) are affected? (Select all that apply)

Other (Deployed)

Additional context

I do not know what the fault is, but I compared how @next/eslint-plugin-next sets its named exports compared to typescript-eslint, which also sets named exports (both being in Common JS (CJS)). An AI summarized it as below. Again, might be wrong, but adding for context:

@next/eslint-plugin-next defines top-level getters on exports Object.defineProperty(exports, "configs", { enumerable: true, get: () => configs }); Node ignores top-level getters for synthetic named exports when importing CJS as ESM.

typescript-eslint works because it assigns a data property at the top level: exports.configs = createConfigsGetters({ ... }); // data property Node sees a top-level data property → creates a synthetic named export → import { configs } works.

To fix @next/eslint-plugin-next do this:

// Instead of top-level getter:
Object.defineProperty(exports, "configs", {
 enumerable: true,
 value: configs  // <- data property, not a getter
});

extent analysis

TL;DR

The issue can be fixed by changing how @next/eslint-plugin-next defines its named exports, specifically by using a data property instead of a getter for configs.

Guidance

  • The error occurs because Node.js ignores top-level getters for synthetic named exports when importing CommonJS (CJS) modules as ES modules (ESM).
  • To fix this, the @next/eslint-plugin-next package should define configs as a data property on the exports object instead of using Object.defineProperty with a getter.
  • As a temporary workaround, you can import the entire package and access configs from it, like this: import pkg from '@next/eslint-plugin-next'; const { configs } = pkg;.
  • Verify the fix by running the same command that previously produced the error: node -e "import {configs} from '@next/eslint-plugin-next';".

Example

// Instead of top-level getter:
Object.defineProperty(exports, "configs", {
  enumerable: true,
  value: configs  // <- data property, not a getter
});

Notes

This fix assumes that the issue is indeed caused by the way @next/eslint-plugin-next defines its named exports. If the issue persists after applying this fix, further investigation may be needed.

Recommendation

Apply the workaround by importing the entire package and accessing configs from it, as this is a more immediate solution that does not require modifying the @next/eslint-plugin-next package directly.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING