vercel/next.js
eslint-plugin-next
Purpose
@next/eslint-plugin-next ships the ESLint rules that flag Next.js anti-patterns in user code. It is the engine behind the next/core-web-vitals and next/recommended configs that ship through eslint-config-next. The plugin's rules catch issues like using <a> for internal navigation, importing next/document from a page, missing keys on next/script, async client components, and Google Fonts misuse.
Source: packages/eslint-plugin-next/src/. Companion config: packages/eslint-config-next/.
Directory layout
packages/eslint-plugin-next/
├── README.md
├── src/
│ ├── index.ts # Plugin entry — registers all rules and configs
│ ├── rules/ # One file per rule (22 rules at this commit)
│ └── utils/ # Shared AST helpers
└── package.jsonThe rule set
Every rule lives at packages/eslint-plugin-next/src/rules/<name>.ts and follows the standard ESLint plugin shape (meta + create).
| Rule | What it catches |
|---|---|
google-font-display |
Google Fonts without display=optional / display=swap |
google-font-preconnect |
Google Fonts without a corresponding <link rel="preconnect"> |
inline-script-id |
<Script> with inline content but no id (would not deduplicate) |
next-script-for-ga |
Use next/script for Google Analytics, not raw <script> |
no-assign-module-variable |
Reassigning the global module variable |
no-async-client-component |
'use client' components declared async |
no-before-interactive-script-outside-document |
strategy="beforeInteractive" outside _document |
no-css-tags |
Inline <link rel="stylesheet"> that should use the bundler |
no-document-import-in-page |
Importing next/document outside pages/_document |
no-duplicate-head |
Multiple next/head instances on a page |
no-head-element |
Raw <head> instead of next/head (Pages Router) |
no-head-import-in-document |
Importing next/head in _document.tsx |
no-html-link-for-pages |
<a> for internal navigation; should use next/link |
no-img-element |
Raw <img> instead of next/image |
no-location-assign-relative-destination |
window.location.assign with a relative URL (breaks in some routers) |
no-page-custom-font |
Custom fonts loaded via next/head instead of next/font |
no-script-component-in-head |
next/script inside next/head |
no-styled-jsx-in-document |
Styled JSX in _document.tsx |
no-sync-scripts |
<script> without async/defer |
no-title-in-document-head |
<title> inside _document.tsx |
no-typos |
Misspelled Next.js exports (e.g. getStaticPropss) |
no-unwanted-polyfillio |
Polyfills for features Next.js already polyfills |
Configs
The plugin also ships two preset configs:
next/recommended— enables most rules atwarnlevel.next/core-web-vitals— enables performance-critical rules aterrorlevel (no async client components, no img, no html link for pages, no css tags, no sync scripts, no unwanted polyfillio).
These are referenced from packages/eslint-config-next/, the package users actually install.
Tests
Each rule has a sibling test file under the rule directory tests pattern (the test files live in test/eslint-plugin-next/ at the repo root). Tests use the standard ESLint RuleTester.
Companion: eslint-config-next
packages/eslint-config-next/ is the package users add to their .eslintrc. It pulls in:
eslint-plugin-reacteslint-plugin-react-hookseslint-plugin-next(this package)eslint-plugin-importfor path resolution
User config:
{
"extends": "next/core-web-vitals"
}Internal lints
packages/eslint-plugin-internal/ is a separate, not published plugin that holds rules used only inside this monorepo. It catches framework-specific patterns like illegal imports across the react-server layer.
Key source files
| File | Purpose |
|---|---|
packages/eslint-plugin-next/src/index.ts |
Plugin entry, rule registration, preset configs |
packages/eslint-plugin-next/src/rules/<name>.ts |
Individual rules |
packages/eslint-plugin-next/src/utils/ |
AST helpers shared across rules |
packages/eslint-config-next/ |
The user-installable preset |
packages/eslint-plugin-internal/ |
Internal-only rules |
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.