Solved: Next.js ESLint Unknown Options 'useEslintrc' and 'extensions' Error
Dharmendra
9 min read
You've just upgraded to ESLint 9, excited to use the latest tooling in your Next.js project. You run next lint like you always do, and then—everything breaks. Your terminal fills with errors about "Unknown options" for things like useEslintrc, extensions, and resolvePluginsRelativeTo.
If you're staring at this Next.js ESLint 9 extensions error wondering what went wrong, you're not alone. This is one of the most common issues developers face after upgrading to ESLint 9, and the good news is it's completely fixable.
In this guide, I'll explain exactly why this happens, walk you through the solutions, and help you avoid this problem in future upgrades.
The Problem — Running 'next lint' with ESLint 9 Fails
When you run npm run lint or next lint in a Next.js project that uses ESLint 9, you get an error that looks something like this:
❌ What you see:➜ npm run lint> lint> next lintInvalid Options:- Unknown options: useEslintrc, extensions, resolvePluginsRelativeTo,
Optimizing RSC and CDN Efficiency for High-Load Next.js Projects
rulePaths,
ignorePath,
reportUnusedDisableDirectives
- 'extensions' has been removed.
- 'resolvePluginsRelativeTo' has been removed.
- 'ignorePath' has been removed.
- 'rulePaths' has been removed. Please define your rules using plugins.
- 'reportUnusedDisableDirectives' has been removed. Please use the 'overrideConfig.linterOptions.reportUnusedDisableDirectives' option instead.
This error is especially frustrating because your ESLint configuration looks perfectly normal. You probably have a standard .eslintrc.json file like this:
{ "extends": "next/core-web-vitals"}
Nothing fancy. Just the basic Next.js recommended setup. So why is it failing?
The issue isn't with your configuration file—it's with how Next.js internally calls ESLint, and ESLint 9 no longer supports those internal calls.
Why ESLint 9 Breaks Next.js Linting
To understand this Next.js ESLint 9 extensions error, you need to know what changed in ESLint 9. ESLint made a massive architectural shift called the "flat config" system.
The Old Way (ESLint 8 and Earlier)
In ESLint 8, you could:
Use .eslintrc.json, .eslintrc.js, or .eslintrc.yaml files
Pass options like --ext .js,.jsx,.ts,.tsx on the command line
Use the useEslintrc option in the Node.js API to control whether config files were loaded
These options were deeply embedded in ESLint's architecture, and tools like Next.js relied on them internally.
The New Way (ESLint 9)
ESLint 9 introduces "flat config" as the default. This means:
Configuration lives in eslint.config.js (a single JavaScript file)
Many CLI options and API parameters were completely removed
The old .eslintrc.* files are deprecated
Here's the list of options that ESLint 9 removed, which Next.js was using internally:
Removed Option
What It Did
useEslintrc
Controlled whether .eslintrc.* files were loaded
extensions
Specified which file extensions to lint
resolvePluginsRelativeTo
Set the base path for resolving plugins
rulePaths
Added custom rule directories
ignorePath
Specified the ignore file path
reportUnusedDisableDirectives
Reported unused ESLint disable comments
The Root Cause
When you run next lint, Next.js doesn't just call ESLint directly. It uses a custom wrapper located in packages/next/src/cli/next-lint.ts. This wrapper passes configuration options to ESLint's Node.js API.
The problem? Next.js was passing options like useEslintrc: true and extensions: ['.js', '.jsx', '.ts', '.tsx'] to ESLint. These options worked fine in ESLint 8, but ESLint 9 throws an error because they no longer exist.
This is a documented issue in the Next.js repository (GitHub Issue #64409), and the Vercel team is aware of it.
The Solution — Getting Your Project Working Again
There are several ways to fix this Next.js ESLint 9 extensions error. Choose the one that best fits your situation.
Solution 1: Downgrade to ESLint 8 (Recommended for Beginners)
The simplest and most reliable fix is to downgrade to ESLint 8. This requires minimal changes and gets your project working immediately.
✅ Expected output:➜ npm run lint> lint> next lint✔ No ESLint warnings or errors
Why this works: ESLint 8 still supports all the options that Next.js internally uses. By downgrading, you restore compatibility until Next.js updates their linting logic.
Solution 2: Use the ESLint CLI Directly (Skip next lint)
If you want to stay on ESLint 9, you can bypass next lint entirely and run ESLint directly. This requires setting up the flat config system.
Step 1: Create an eslint.config.mjs file in your project root:
// eslint.config.mjsimport { FlatCompat } from "@eslint/eslintrc";import path from "path";import { fileURLToPath } from "url";const __filename = fileURLToPath(import.meta.url);const __dirname = path.dirname(__filename);const compat = new FlatCompat({ baseDirectory: __dirname,});export default [ ...compat.extends("next/core-web-vitals"), { ignores: [".next/*", "node_modules/*"], },];
Step 2: Install the compatibility package:
npm install @eslint/eslintrc --save-dev
Step 3: Update your package.json script to use the ESLint CLI directly:
Step 4: Remove or rename your old .eslintrc.json file (ESLint 9's flat config won't use it):
mv .eslintrc.json .eslintrc.json.backup
Now npm run lint will use ESLint directly, bypassing Next.js's wrapper entirely.
Trade-offs: This approach works, but you lose some Next.js-specific linting features that next lint provides, such as automatic caching and integration with the build process.
Solution 3: Use the ESLINT_USE_FLAT_CONFIG Environment Variable
ESLint 9 provides an escape hatch to temporarily use the legacy configuration system:
ESLINT_USE_FLAT_CONFIG=false npm run lint
Or add it to your npm script:
{ "scripts": { "lint": "ESLINT_USE_FLAT_CONFIG=false next lint" }}
Important: This is a temporary workaround. ESLint has deprecated the legacy config system, and future versions may remove this option entirely. Use this only as a short-term fix while you plan your migration.
Solution 4: Wait for Next.js to Add ESLint 9 Support
The Next.js team is actively working on ESLint 9 support. If you're not in a rush, you can:
Upgrade to ESLint 9 once Next.js releases official support
Prevention & Best Practices
Now that you've fixed the immediate problem, let's talk about how to avoid similar issues in the future.
1. Check Compatibility Before Upgrading
Before upgrading any major dependency in your Next.js project, check compatibility with eslint-config-next:
# Check the current version of eslint-config-nextnpm list eslint-config-next# Check which ESLint versions it supportsnpm info eslint-config-next peerDependencies
As of early 2024, eslint-config-next still lists ESLint 8 as a peer dependency. Upgrading ESLint beyond what's officially supported is asking for trouble.
2. Pin Your Dependencies
Instead of using caret (^) or tilde (~) version ranges, consider pinning major dependencies:
This prevents accidental upgrades when running npm install on a fresh clone.
3. Read the Changelog Before Major Updates
ESLint's migration guide (eslint.org/docs/latest/use/migrate-to-9.0.0) clearly documents all breaking changes. Spending 10 minutes reading changelogs can save hours of debugging.
4. Test in Isolation
Before upgrading ESLint in your main project, test the upgrade in a branch or a minimal reproduction:
# Create a test branchgit checkout -b test/eslint-9-upgrade# Attempt the upgradenpm install eslint@9 --save-dev# Run lintingnpm run lint# If it fails, you haven't affected your main branchgit checkout main
5. Watch for Next.js Release Notes
Major Next.js releases often include ESLint-related updates. Check the release notes at nextjs.org/blog before upgrading to understand what's changed.
Understanding the Flat Config System
If you're curious about ESLint's flat config system, here's a quick primer. Understanding this will help you when Next.js eventually requires ESLint 9.
The flat config is a single eslint.config.js (or .mjs, .cjs) file that exports an array of configuration objects:
No more cascading config files (.eslintrc in every directory)
Plugins are imported directly, not referenced by string
extends is replaced by spreading arrays
The configuration is more explicit and predictable
Key Takeaways
The error is caused by ESLint 9, not your configuration. ESLint 9's flat config system removed options that Next.js internally uses.
Downgrading to ESLint 8 is the simplest fix for most projects and has no downsides for now.
You can bypass next lint and use ESLint directly with flat config if you need ESLint 9 features.
This is a known issue tracked in GitHub Issue #64409. The Next.js team is working on it.
Always check compatibility before upgrading major dependencies, especially linting tools that integrate deeply with your framework.
Next Steps
Fix the immediate issue by downgrading to ESLint 8 using npm install eslint@8 --save-dev
Pin your ESLint version in package.json to prevent accidental upgrades
Bookmark GitHub Issue #64409 to get notified when Next.js adds ESLint 9 support
Learn about flat config so you're ready when Next.js migrates—the ESLint migration guide is an excellent resource
Test your linting after any major upgrade by running npm run lint before committing changes
The Next.js ESLint 9 extensions error is frustrating, but it's a temporary pain point in the JavaScript ecosystem's evolution. ESLint's flat config is genuinely better architecture, and once the ecosystem catches up, these issues will be behind us.
High-traffic Next.js applications often suffer from poor CDN cache hit rates due to how React Server Component payloads are hashed during client-side navigation. This guide uses real performance benchmarks to demonstrate fixes that dramatically improve edge caching efficiency.
Fix: TypeError: Cannot read properties of null (reading 'auth') on Next.js \_not-found
When your Next.js build fails with "TypeError: Cannot read properties of null (reading 'auth')" on the \_not-found page, it's usually because your layout tries to access authentication context during static prerendering. Here's how to fix it properly.
How to Bypass Next.js Cache Components for Draft Mode Preview
Next.js Cache Components introduce a powerful static shell optimization, but they conflict with draftMode preview workflows. Learn how to conditionally bypass caching when editors need to preview unpublished content from your headless CMS.