The misleading thing about this error is that your app keeps working. next dev and next build run fine, the browser renders normally — but open a .ts/.tsx file in VS Code or run npx eslint . and you get:
Parsing error: Cannot find module 'next/babel'
Require stack:
- /Users/mahdi/Projects/my-next-app/node_modules/eslint-config-next/parser.js
- /Users/mahdi/Projects/my-next-app/node_modules/next/dist/compiled/babel/eslint-parser.js
- /Users/mahdi/Projects/my-next-app/node_modules/eslint/lib/cli-engine/config-array-factory.js
It shows up most after upgrading from Next.js 12 to 13+, or right after scaffolding a fresh App Router project. It is identical on macOS, Linux, and Windows. The reason the app still compiles is the key to the fix.
Two resolution contexts that never talk to each other
Next.js 13+ ships SWC as the default compiler and deprecated the next/babel preset for user-facing config — but next/babel still exists inside the next package's internal build pipeline. Next.js resolves it at runtime through its own bundler, not through Node's require(). So next dev works.
ESLint is a different process. It runs in plain Node.js and resolves modules the standard way — from wherever it is invoked. When a stale ESLint config points the parser at next/babel (parser: 'babel-eslint' or parserOptions: { parser: 'next/babel' }), ESLint calls require.resolve('next/babel') from its own working directory. In a monorepo, a pnpm workspace, or simply a fresh SWC project that never installed the Babel toolchain, that resolution fails. The preset was not deleted — ESLint just cannot see it from where it stands.
That is the whole conflict: ESLint and Next.js have separate module-resolution contexts, and next/babel only lives in Next.js's. The error is not about credentials or a broken install; it is about which tool is looking, from where.
The config that fixes it
Stop pointing ESLint at next/babel and let eslint-config-next configure the parser itself:
// .eslintrc.json
{
"extends": [
"next/core-web-vitals"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": ["./tsconfig.json"],
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/no-unused-vars": "error"
}
}
eslint-config-next (bundled with Next.js 13+) wires ESLint to @typescript-eslint/parser and skips the deprecated next/babel path. Setting parser and parserOptions.project explicitly makes ESLint resolve TypeScript against your real tsconfig.json instead of a phantom Babel preset.
Steps:
- Open
.eslintrc.json(or.eslintrc.js). - Find any
parser: 'babel-eslint'orparserOptions: { parser: 'next/babel' }entries. - Replace the whole config with the snippet above; use
"next/core-web-vitals", not"next"alone. - Save, then restart the ESLint server in VS Code (Cmd/Ctrl+Shift+P → "ESLint: Restart ESLint Server").
In a monorepo (Nx, Turborepo), point parserOptions.project at every tsconfig.json — see Special case: monorepos below.
Verify
npx eslint .
You want:
All files passed linting.
Found 0 errors.
If the error persists, two caches usually hold it open:
VS Code's ESLint extension cached the old config. Delete the cache and restart the server — note npx eslint --cache does not clear it, it creates/updates it:
rm .eslintcache
Then Cmd/Ctrl+Shift+P → "ESLint: Restart ESLint Server".
A leftover .babelrc or babel.config.js. Next.js 13+ does not read these by default — it uses next.config.js for compiler settings — but ESLint may still try to load next/babel as a preset from them. Delete the file unless you genuinely need custom Babel plugins. If you must keep it:
// babel.config.json
{
"presets": [
["next/babel", { "preset-env": { "useBuiltIns": "usage" } }]
]
}
Prefer deleting it and letting Next.js handle Babel/SWC internally.
Special case: monorepos (Nx, Turborepo, Lerna)
In monorepos, ESLint's parserOptions.project must point to all tsconfig.json files — not just the root one. In an Nx workspace:
// .eslintrc.json
{
"extends": ["next/core-web-vitals"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": [
"apps/*/tsconfig.json",
"libs/*/tsconfig.json"
],
"sourceType": "module"
}
}
Omit this and ESLint cannot resolve types across workspaces, so type-aware rules fail. This is why next lint works in Nx but npx eslint apps/web/src/page.ts fails.
For Turborepo, make sure turbo.json includes ESLint in the pipeline:
{
"pipeline": {
"lint": {
"outputs": ["{workspaceRoot}/.eslintcache"],
"cache": false
}
}
}
Run turbo run lint — not npx eslint directly — to get Turborepo's workspace-aware resolution.
Modern alternative: transitioning from Babel to SWC
Next.js 13+ defaults to SWC, and next/babel is obsolete for new config. If you are still on Babel (e.g., for custom plugins), migrate to SWC by:
- Deleting
.babelrc,babel.config.js, and@babel/*dependencies. - Adding
next.config.js:
// next.config.js
module.exports = {
compiler: {
// Remove this if you need Babel features
// styledComponents: true,
}
};
- Pointing ESLint at
@typescript-eslint/parser(as above).
SWC is roughly 17x faster than Babel and eliminates the next/babel resolution issue entirely — it does not use Babel presets at all. I go deeper on this in Next.js App Router Guide: From Basics to Advanced Patterns.
FAQ
Do I need to install @babel/core to fix this error?
No — Next.js bundles @babel/core internally. Installing it manually often causes version conflicts (e.g., @babel/core@7.20.0 vs Next.js's 7.22.0). The fix is purely configuration: update ESLint to use @typescript-eslint/parser, not babel-eslint.
Will switching to SWC remove the need for next/babel?
Yes — SWC is Next.js's native compiler and does not use Babel presets. On Next.js 13+ you are already on SWC unless you explicitly opt into Babel via next.config.js. No next/babel configuration is needed.
Why is this error only showing up in VS Code and not during the build?
VS Code's ESLint extension runs in a separate process with its own resolution rules. next build uses Next.js's internal compiler, which resolves next/babel at runtime — not via Node.js require(). That is why your app compiles fine while ESLint fails.
How do I disable the specific ESLint rule if using a custom compiler?
If you must use a custom Babel setup (e.g., for styled-components), add to .eslintrc.json:
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": ["./tsconfig.json"],
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-unused-vars": "off"
}
}
Prefer SWC unless you need Babel-specific features.
Related
- Next.js Hydration Mismatch: 8 Fixes for App Router (2026)
- AI Integration for Next.js + Supabase Applications
- Deploying Next.js + Supabase to Production
- How to Structure Your Next.js App Router Project for Scale
- Next.js 16 Removed next lint: ESLint 9 Migration
- Next.js & Supabase Masterclass: Robust CI/CD Pipelines with GitHub Actions
Originally published at https://www.iloveblogs.blog
Top comments (0)